useCallback

React provides a set of powerful hooks to manage state and side effects in functional components. One such hook is useCallback, which helps optimize performance in certain situations.

What is useCallback?

useCallback is a React Hook that returns a memoized version of a callback function. This means that React will remember the function you pass and only recreate it when its dependencies change.

It’s commonly used to prevent unnecessary re-creation of functions, especially when passing them to child components or using them in dependencies.

Syntax

const memoizedCallback = useCallback(() => {
// your function logic
}, [dependencies]);
  • () => {}: This is your callback function.
  • [dependencies]: This is the dependency array. If any value here changes, the function will be re-created.

Why Use useCallback?

In React, every time a component renders, functions are re-created. This is usually fine, but in some cases, especially when:

  • A function is passed to a child component as a prop,
  • Or used inside an effect like useEffect or useMemo,

…it can cause unnecessary re-renders or logic re-executions.

useCallback helps avoid this by caching the function, so its reference stays the same unless it actually needs to change.


Problem Without useCallback

Here’s an example where a child component receives a function as a prop:

 function Parent() {
const [count, setCount] = useState(0);

const increment = () => setCount(count + 1);

return <Child onClick={increment} />;
}

Every time Parent re-renders, the increment function is re-created. This causes the Child component to think the prop changed, even if it didn’t.


Solution Using useCallback

function Parent() {
const [count, setCount] = useState(0);

const increment = useCallback(() => {
setCount((prev) => prev + 1);
}, []);

return <Child onClick={increment} />;
}

Now, increment has a stable reference. It only changes if the dependencies (in this case, none) change. So the Child component won’t re-render unnecessarily.


Real-World Example with React.memo

 const Button = React.memo(({ onClick, label }) => {
console.log("Rendering:", label);
return <button onClick={onClick}>{label}</button>;
});

function App() {
const [count, setCount] = useState(0);
const [theme, setTheme] = useState("light");

const increment = useCallback(() => {
setCount((prev) => prev + 1);
}, []);

return (
<>
<Button onClick={increment} label="Increment" />
<button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
Toggle Theme
</button>
<div>Count: {count}</div>
</>
);
}

Here, the Increment button won’t re-render when we toggle the theme, because increment is memoized with useCallback.


When to Use useCallback

Use useCallback only when needed — such as when:

  • You’re passing a callback to a memoized child component (React.memo).
  • The callback is used in a dependency array (like in useEffect, useMemo).

Tip: Performance Consideration

Using useCallback everywhere does not improve performance — in fact, it can hurt performance if overused because it also takes memory and processing to manage dependencies. Only use it when a function being re-created causes an issue.


Conclusion

useCallback is a helpful optimization tool in React that memoizes your functions and avoids unnecessary re-renders or executions. Use it wisely when you’re dealing with performance-sensitive components, especially when passing callbacks to children or inside dependency arrays.