Skip to main content

useCallback

The useCallback hook in React is used to memoize a function, so that the function instance remains the same if its dependencies haven't changed. This is useful for optimizing performance, particularly in scenarios where passing a callback to child components could cause unnecessary re-renders if the function instance changes.

Basic Syntax​

The basic syntax of useCallback is as follows:

const memoizedCallback = useCallback(
() => {
// Your function logic here
},
[dependency1, dependency2, ...]
);

Here, the function you want to memoize is the first argument, and the array of dependencies is the second argument.

How it Works​

  1. Define Function: You define the function you want to memoize within useCallback.

    const fetchData = useCallback(() => {
    // Fetch data logic
    }, [dependency]);
  2. Specify Dependencies: You specify an array of dependencies. The function will be re-memoized only when one of these dependencies changes.

    const fetchData = useCallback(() => {
    // Fetch data logic
    }, [url, options]);
  3. Use Memoized Function: You can now use this memoized function in your component logic or pass it down to child components.

    <ChildComponent fetchData={fetchData} />

Examples​

Here's a simple example to demonstrate how useCallback can be used:

Live Editor

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

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

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
}

Result
Loading...
Live Editor
function App() {

  const [count, setCount] = useState(0);
  const effectBtn = useRef(null);

  /*const onCLickHandler = () => {
    console.log("The count value from  effect btn click"+ count)
  }*/
  
  const onCLickHandler = useCallback( () => {
    console.log("The count value from  effect btn click"+ count)
  }, [count]);

  useEffect(()=> {
    const btn = effectBtn.current;
    console.log("1) >>>---> The count value from use effect "+ count)

    btn.addEventListener("click", onCLickHandler);
  }, []);

  return (
    <>
        <input type='number' value={count} id='countId' readOnly />
        <button onClick={() =>  setCount(count + 1)}>Increase</button>
        <button ref={effectBtn}>Effect Count</button>
        <br />
        <br />
        <p style={{color: "red"}}> Open consol tab and check logs printing, observe Increase button and Effect Count</p>
    </>
  );
}
Result
Loading...

In this example, the increment function is memoized using useCallback. It only changes when count changes, so if you pass increment to a child component, the child won't re-render unless count changes.

Use Cases​

  • Preventing Unnecessary Renders: When passing callbacks to child components that are optimized with React.memo, useCallback ensures that the child only re-renders when the actual logic of the function changes.

  • Dependency Arrays: In hooks like useEffect, if a function is a dependency and it changes every render, it could lead to an infinite loop. Using useCallback can prevent this.

Caveats​

  • Overusing useCallback can lead to more harm than good. Memoization itself has a cost, so if the function is not complex and doesn't trigger frequent re-renders, it might be better not to use useCallback.

  • Make sure to correctly specify all dependencies to avoid stale closures, where the function captures outdated variables.

Summary​

The useCallback hook is used to memoize functions based on specified dependencies, helping to optimize performance by preventing unnecessary re-renders in child components. However, it should be used judiciously, keeping in mind the cost of memoization.