Optimize React Render using useMemo, useCallback, and React.memo
Maintaining code that have so many contributor is harder than I thing, don’t you agree? It’s a first time in 2022 that I work with company that have many developer on frontend site and there is a chance that your coworker did some anti-pattern and made the app slower than before.
You can read more about React antipattern here
Today I will share how to Optimize React Application and the most popular way to do this is using useMemo, useCallback, and React.memo.
What is re-render in React?
When talking about React performance, there are two major stages that we need to care about:
- initial render — happens when a component first appears on the screen
- re-render — second and any consecutive render of a component that is already on the screen
When React components re-render itself?
There are four reasons why a component would re-render itself:
- state changes
- parent (or children) re-renders
- context changes,
- hooks changes
useMemo vs useCallback
Fundamentally, useMemo
and useCallback
are tools built to help us optimize re-renders. They do this in two ways:
- Reducing the amount of work that needs to be done in a given render.
- Reducing the number of times that a component needs to re-render.
Simple explanation:
- useMemo returns a memoized value.
const memo = useMemo(() => fn, deps)
- useCallback returns a memoized callback
const callback = useCallback(fn, deps)
useMemo
Our application has two pieces of state, selectedNum
and time
. Once per second, the time
variable is updated to reflect the current time, and that value is used to render a digital clock in the top-right corner.
Here’s the issue: whenever either of these state variables change, we re-run all of those expensive prime-number computations. And because time
changes once per second, it means we're constantly re-generating that list of primes, even when the user's selected number hasn't changed!
Solution : You can wrap the allPrimes function with React.useMemo, This will prevent the allPrimes being called every seconds.
useMemo
takes two arguments:
- A chunk of work to be performed, wrapped up in a function
- A list of dependencies
In this case, we’re essentially saying “recalculate the list of primes only when selectedNum
changes”. When the component re-renders for other reasons (eg. the time
state variable changing), useMemo
ignores the function and passes along the cached value.
This is commonly known as memoization, and it’s why this hook is called “useMemo”.
useCallback
useCallback
serves the same purpose as useMemo
, but it's built specifically for functions. We hand it a function directly, and it memoizes that function, threading it between renders.
Instead of returning an array, we’re returning a function. This function is then stored in the calculate
variable.
This works… but there’s a better way:
React.memo
Alternatively you can use React.memo to prevent the re-renders
Wrapping a component in React.memo
will stop the downstream chain of re-renders that is triggered somewhere up the render tree, unless this component’s props have changed.
This is known as a pure component. Essentially, we’re telling React that this component will always produce the same output given the same input, and we can skip the re-renders where nothing’s changed.
This can be useful when rendering a heavy component that is not dependent on the source of re-renders (i.e. state, changed data).
This is so important because if you have many components within 1 file and you want only render 1 component, React.memo is the answer.
Bonus Tips
Creating components inside render function of another component is an anti-pattern that can be the biggest performance killer. On every re-render React will re-mount this component (i.e. destroy it and re-create it from scratch), which is going to be much slower than a normal re-render.
If you liked this article, you might want to clap for it because it would help me out a lot. Thank you!