2.2.6: React useMemo - useCallback
Introduction
Weโve talked about useState and useEffect which is the building block of all React application. You can arguably create any React project with just these two hooks.
As your app scales, you might find that these hooks alone might not be enough to create an optimised application because thereโll be lots of state changes and side-effect that will be happening and it might slow your app down.
This is why React comes with some built-in hooks to help alleviate this
Hereโs a list of additional React hooks from their documentation.
Before we dive in, letโs take a look at one of the technique React uses called memoization
Memoization
So what is memoization?
From wikipedia -
โฆ memoization is an optimisation technique used primarily to speed up computer programs by storing the results of expensive function calls and returning the cached result when the same inputs occur again
The key takeaways are:
Optimisation technique
Speed things up
Returns cache result if input is the same
Letโs take a look at an example of an expensive function call by implementing the Fibonacci number of N sequence
function fibonacci(n) {
if (n < 2) return 1;
return fibonacci(n - 1) + fibonacci(n - 2);
}
// What is the "4th" sequence in the Fibonacci's number?
fibonnacci(4)
// Answer: 3
// What is the "20th" sequence in the Fibonacci's number?
fibonnacci(20)
// Answer: 10946
// What is the "50th" sequence in the Fibonacci's number?
fibonnacci(50)
// Answer: uh oh something brokeAs you can see, if you were to find the โ50thโ sequence in Fibonacciโs number using the code above, things start to break*.* The reason it broke is because our recursive call still calculates the value of the previous functions even when it has calculated it before
Example of how it looks like

This is where memoization comes in, so letโs optimise it by returning the cache result of our function instead!
Weโve introduced an additional param to our function called cache and set the value of it to be an empty array if it doesnโt exists.
This stores the previous value of our result and we send the value to our function so that the program doesnโt need to recompute the value again and again and again and again and again.
This will lay the foundation of how memoization works
React.memo
One of the API that React provides us that helps with performance is React.memo
React.memo is a higher order component and is used as a performance optimisation by memoizing the result
Take for example a button component below
When my App loads, it will render the Button component
Inside my App, if a user types in the input, it will call the function changeText which will call setText and re-render the components
This might seem minor but on a page with many components, we donโt really want a simple Button component to re-render every time a user types right?
This is where React.memo comes in and is a handy way to optimise unnecessary re-renders
By simply wrapping it in React.memo whenever state changes in my App it will not cause a re-render of the Button component! React will skip rendering the component, and reuse the last rendered result.
๐ก A good way to know when to use it for a component is if the component renders the same result given the same props.
useMemo
Returns a memoized value.
This is the equivalent of React.memo that we encountered except that itโs for values.
Below, we changed the Button component to track a count state. Every-time we click the button, we will add 1 to count. We also implemented the fibonacci sequence from above and plugged it into our App
Notice how whenever we clicked on the Button component to add to the counter, our whole App re-renders again and we will have to recalculate our fibonacci number even though the num state didnโt change.
This is an issue especially if the number is big and our function will be really expensive to compute.
Luckily, this is where useMemo comes in and optimises the performance by skipping the calculation part if the input hasnโt changed! In essence, we memoized the result and from useMemo and we keep track of the input of num in the dependency array.
useCallback
If you ran the code above, youโll actually realise that our previous Button component that we wrapped in React.memo actually is re-rendering again.
Hmm, but nothing changed right? If you look a little closer, this time we are passing in a prop called handleOnClick which takes in a function.
Well if you passed in a primitive value such as a string or an integer, it wonโt cause a re-render if the value remained the same, but why did passing in a function caused an issue?
The real reason is because functions are compared by reference and not by value. The code below illustrates this example:
Whenever React re-renders, the function will be re-generated on every single render, producing a unique function each time. That is to say that the function we passed on to our Button component has โchangedโ on each render, causing it to re-render again!
Fortunately, React has provided us with the useCallback hook that will allow us to keep that function that we created to be the same handleCounterClick every time.
The Button component now will not re-render unnecessarily and we have optimised our App to be more performant.
Conclusion
Despite learning how to make our app more performant, itโs not always necessary to use these hooks. Remember that they are there as tools to help when things feel sluggish or slow. React is a very powerful library that knows how to optimise itself even without using the hooks that we have learned.
Hereโs a great article on when you should use the hooks that we have learned by Kent C. Dodds
When to useMemo and useCallback
Resources
If Hereโs a really great resource by Josh W Comeau that takes deep dive into what we just went through.