When passing callback functions down to child components as props, React will re-render those child components unnecessarily even if the callback functions remain the same. This behavior occurs because JavaScript treats functions as objects, and every time the parent component renders, it creates a new function instance. Even if we use the React.memo() in the child component, it won't prevent re-rendering as the reference of the callback function changes.
To address this problem, React provides a hook called useCallback that memoizes a callback function. This means it memoizes the function instance between renders, ensuring that a new function is not created on every render unless its dependencies change.
Syntax of useCallback hook
The useCallback hook in React accepts two parameters.
functionToCache: The callback function that you want to memoize.
dependencies: An array of dependencies that, when changed, will cause the callback to be re-created.
Usage of useCallback hook
Let's consider an example where a button is rendered in both parent and child components which increments a counter when clicked. The function to increment the child counter is passed as a prop to the child from the parent. Additionally, we have memoized the child component.
Now, let's examine this scenario without using the useCallback hook:
Every time the parentCount state changes, the parent component re-renders, creating a new instance of the incrementCount function. This causes the child component to re-render, making the React.memo wrapping ineffective.
This is where the useCallback hook comes to your rescue. We will wrap the incrementCount function inside a useCallback hook, ensuring that the Child is only re-rendered when the childCount changes.
You may now observe that rendering child is logged to the console only when we click the Child counter button.
Note that this example is provided to demonstrate the functionality of the useCallback hook. It is not necessary to use the useCallback hook in this case, as the Child component is light and its re-rendering doesn’t affect performance. Only use useCallback on truly performance-critical callback functions.