Blog>
Snippets

Handling Cleanup in useCallback Memoization

Provide an example of using the useCallback hook in React 18 to memoize callbacks and prevent unnecessary re-renders, including a cleanup function.
import { useCallback, useState, useEffect } from 'react';

function ExampleComponent(props) {
  // State to trigger re-renders
  const [trigger, setTrigger] = useState(false);

  // Callback memoized with useCallback so it's not recreated every render
  const memoizedCallback = useCallback(() => {
    // ... actions that should be memoized ...

    // Cleanup function to run when the callback is no longer needed
    return () => {
      // ... cleanup actions ...
    };
  }, []); // Empty array means the callback will not update between renders

  // Triggering to see the effect of the cleanup
  useEffect(() => {
    return () => memoizedCallback(); // This invokes the cleanup on component unmount or before re-running the effect
  }, [trigger]); // Depends on the 'trigger' to re-run the effect

  // Function to update the trigger state, causing a re-render
  const updateTrigger = () => setTrigger(prev => !prev);

  return (
    <div>
      <button onClick={updateTrigger}>Trigger re-render and cleanup</button>
    </div>
  );
}

export default ExampleComponent;
This code snippet demonstrates how to use the useCallback hook within a React functional component. A memoized callback is created, including a cleanup function that will run when the callback is no longer needed or before it's re-created due to dependencies changing. In this example, the dependencies array is empty, meaning the callback won't update between renders. The cleanup function is invoked during the cleanup phase of useEffect, simulating a scenario where the cleanup is required on component unmount or before re-running the effect, as it's tied to the component's 'trigger' state. A button is provided to toggle the state, which in turn triggers the effect's cleanup.