I'm trying to understand what the use case is for using React's useCallback
hook in place of the useEffect
hook.
They both appear to act as a listener for state changes of their inputs (examples taken from the React Docs):
useEffect( () => { const subscription = props.source.subscribe(); return () => { subscription.unsubscribe(); }; }, [props.source], ); const memoizedCallback = useCallback( () => { doSomething(a, b); }, [a, b], );
But, the useEffect
hook gives the additional benefit of cleaning up resources where you would have previously with componentWillUnmount
.
So, what is a good use case for using useCallback
? And, what am I missing here?
The useCallback hook is used when you have a component in which the child is rerendering again and again without need. Pass an inline callback and an array of dependencies. useCallback will return a memoized version of the callback that only changes if one of the dependencies has changed.
Hence, inside the List component, useEffect hook calls the setItems and prints “Fetching items” as its dependency has changed. The solution to the above problem: Here we can use the useCallback function to memoise the getItems() function depending upon the input number.
The useEffect Hook allows you to perform side effects in your components. Some examples of side effects are: fetching data, directly updating the DOM, and timers. useEffect accepts two arguments. The second argument is optional.
The useOnUnmount() hook is a functional React alternative to the ComponentWillUnmount lifecycle method that allows us to mutate values between renders so that it can be used outside the component.
useEffect
has very specific timing aspects related to it that you can read about here. The function specified will be executed after rendering is complete and the DOM has been updated. This will happen after each rendering where any of the values specified in the second-argument array change.
useCallback
doesn't automatically execute anything. It returns a function that can be executed by whatever code needs to trigger it. There is no listening to changes that causes an execution of the callback. The array values just control what instance of the function is returned. The array values do not control the timing of the function execution.
A key use case is to pass this function as a prop to a child component to use as an event handler. useCallback
allows you to define an inline function to use as an event handler (thus it has access to any other variables in the context where the function is defined) without the downside of passing a unique prop to the child every render. So long as the values in the second-argument array have not changed, the same function will be returned as was returned the previous rendering. So if the child component is a pure component, it will not be forced to re-render simply because of always receiving a unique event handler function.
without useCallback
const Parent = ()=> { const [a, setA] = useState(null); const eventHandler = ()=> { // every render creates a unique instance of eventHandler // even though it always does the same thing so long as 'a' hasn't changed doSomethingWithA(a); } return <Child onClick={eventHandler}/> }
with useCallback
const Parent = ()=> { const [a, setA] = useState(null); const eventHandler = useCallback(()=> { // A unique function instance is passed in to useCallback on every render, but // eventHandler will be set to the first instance of this function // (i.e. potentially an instance of the function that was passed to useCallback // on a previous rendering) that was passed to useCallback // for the current value of 'a'. doSomethingWithA(a); }, [a]); return <Child onClick={eventHandler}/> }
This article provides a bit more detail than the React docs on the use case for useCallback
and other hooks.
Related answer: Trouble with simple example of React Hooks useCallback
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With