Ajoutez des adhésions à votre projet Webflow en quelques minutes.
Plus de 200 composants Webflow clonables gratuits. Aucune inscription n'est nécessaire.
Ajoutez des adhésions à votre projet React en quelques minutes.
What is the useCallback hook in React?
The useCallback hook returns a memoized callback function. Memoization is an optimization technique in program development that stores some computed value in memory and can be accessed without having to recompute that value.
Think of memoization as a cache, such that as long as the inputs don’t change, the cached value is used. But if the inputs change, the value is recomputed.
This callback function from the useCallback hook only changes when the specified dependencies that the function depends on, changes. Here’s the syntax:
The dependencies array specifies what this hook depends on. When any of the dependency changes, the hook redeclares the function and caches it.
Why do we need the useCallback hook?
In general, memoization is a great way to improve program speed, and improve user experience by avoiding to recompute the same values over and over again. The useCallback hook helps us to achieve this in functional components.
With this hook, we can save expensive functions (slow functions, or functions using many resources) in memory, and only have to execute them when we need to.
Example/Usecase of the useCallback hook
Avoiding recomputations due to referential equality
The most common reason why you would want to use this hook is to avoid referential equality problems. And this is found in objects. In JavaScript, objects, no matter how similar are not equal to each other because they have different references.
This inequality in references is very common when you’re using a function as a dependency, for example, in a useEffect hook. This may cause the useEffect hook to be triggered when you do not expect. Let’s look at some React code to understand this better.
Let’s say we have the following project.
This basic project has two components: the ProductList component which takes a getProduct function prop and the App component.
The getProduct function is passed from the App component to the ProductList component, which calls the function in a useEffect hook, updates the products state, and displays the returned value on the UI. The getProduct function is also a dependency for the useEffect hook so that the function is only called when it changes.
This getProduct function is assumed to make an API call (which could be slow) when it is evoked. Here’s the problem with this setup.
In React, when the state in a component changes, the component is re-rendered, every value is recomputed and every declaration re-declared. This means that when the query state changes:
- the getProducts function is redeclared, and the getProducts function in the previous state is NOT EQUAL to the getProducts function in the new state (because in JavaScript. objects no matter how similar are not equal to each other)
- in the ProductList component, the getProducts function is re-executed because the useEffect hook believes that the getProducts dependency has changed
This is what we want. The query changes, and a new set of products is fetched and displayed on the screen. But, what if the number state changes? Same thing happens. The get products function is redeclared, the get products function re-executed again in the Product List component.
As a way to improve this, we want to optimize this component to “save” the get products function and not to have to make API calls every time the state changes. The only time we want to make a new API call is if the query state changes, so that we can get a new set of products.
We can improve this with the useCallback hook like so:
By memoizing the getProducts function, it does not get redeclared on rerender when the number state changes. This means, the reference stays equal in the useEffect hook of the List component, hence, the useEffect hook is not triggered.
By passing a query dependency, the getProducts function will be redeclared when the query state changes, and also triggering the useEffect hook—which is just what we want.
When should you not use the useCallback hook
You shouldn’t use the useCallback for solving every reference equality problems. Yes, it seems like a nice solution to avoid redeclarations all the time but one thing to note here is, memoization is a technique that involve saving some data to memory. Memoizing every part of your application uses more memory resources and this can negatively affect the performance of your application.
You should only use this hook when a function repeatedly executed can result in a bad user experience. For example, expensive or slow API calls. But for a function that does simple calculations, there’s no problem having that executed every time.
useCallback vs useMemo
Just like the useCallback hook, the useMemo hook is used for memoizing values in functional components. The difference between both hooks is that useCallback returns a memoized callback function while useMemo returns a memoized value.
That is, on using the useMemo hook, the callback function passed to it is executed, and a memoized value returned to the variable. But with the useCallback hook, the callback function passed to it is memoized and returned to the variable.
Here’s a code block to explain this:
It’s also worth noting that the useCallback takes a callback function as an argument which can also have arguments. For example:
This makes it easy to reuse functions. But you cannot do the same with the useMemo hook.
Conclusion
In this article, we’ve seen what the useCallback hook is, how it works, a use case for it, when you shouldn’t use it and how it compares to the useMemo hook.
To reiterate, this hook is used for memoizing functions in React, which can be very useful for executing such functions when you need to, and not when a random state changes.