How to avoid unnecessary re-render in React
React is pretty popular right now, and there’s plenty of documentation out there that can help you prevent re-rendering components over and over again. However, many new Devs also sometimes find it difficult to fix the fact that their components keep re-rendering when they are not needed. There are actually ways to avoid this re-render problem.
In this article, we will discuss 5 ways to avoid unnecessary re-rendering in React components.
1. Memoization using useMemo() and UseCallback() Hooks
Memoization only allows your code to re-render components if there are changes in the props
. With this technique, you can avoid unnecessary renders and reduce the computational load in your applications.
React provides two Hooks to perform Memoization :
useMemo()
UseCallback()
These Hooks reduce re-render by caching and returning the same result if the inputs are the same without any computation. When the input changes, the cache is invalidated and the new state component is re-rendered .
useMemo()
To understand how to use the useMemo()
Hook, consider an example of multiplying 2 numbers.
1 2 3 4 | <span class="token keyword">const</span> <span class="token function-variable function">multiply</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token parameter">x <span class="token punctuation">,</span> y</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> x <span class="token operator">*</span> y <span class="token punctuation">}</span> |
The above function will compute the result and re-render the component every time it is called, regardless of the input. However, if we use the useMemo()
Hook, we can avoid re-rendering the component if the input is the same and cache the result.
1 2 | <span class="token keyword">const</span> cachedValue <span class="token operator">=</span> <span class="token function">useMemo</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">multiply</span> <span class="token punctuation">(</span> x <span class="token punctuation">,</span> y <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> x <span class="token punctuation">,</span> y <span class="token punctuation">]</span> <span class="token punctuation">)</span> |
Now, the calculation result is stored in the cachedValue
variable and the useMemo()
Hook will return that result unless the input is changed to perform the calculation again.
UseCallback()
UseCallback
is another React Hook to perform Memoization. But, unlike ()
useMemo()
, it doesn’t cache the results. Instead, it stores the callback function provided to it.
For example, consider a component with a clickable item list.
1 2 3 4 5 6 7 8 9 10 11 | <span class="token keyword">import</span> <span class="token punctuation">{</span> useCallback <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">MyParent</span> <span class="token punctuation">(</span> <span class="token parameter"><span class="token punctuation">{</span> term <span class="token punctuation">}</span></span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> onClick <span class="token operator">=</span> <span class="token function">useCallback</span> <span class="token punctuation">(</span> <span class="token parameter">event</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token string">'Clicked Item : '</span> <span class="token punctuation">,</span> event <span class="token punctuation">.</span> currentTarget <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> item <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span> Listitem <span class="token operator">=</span> <span class="token punctuation">{</span> item <span class="token punctuation">}</span> onClick <span class="token operator">=</span> <span class="token punctuation">{</span> onClick <span class="token punctuation">}</span> <span class="token operator">/</span> <span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
In the above example, useCallBack()
stores the callback of the function that was called when the onClick
event was triggered. So it won’t render the component again if the user clicks on the same item multiple times.
2. Optimize API Calls with React Query
It is very common to use useEffect()
Hook for asynchronous fetch operations in React applications. However, when useEffect()
fetches data on every render and in most cases it keeps loading the same data.
We have a solution to solve this that can use the React Query library to store response
data. When we make an API call, React Query will first return data from the cache before continuing with the request
. It will then retrieve the data from the server and if there is no new data, it will prevent the component from re-rendering.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> useQuery <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-query'</span> <span class="token keyword">import</span> axios <span class="token keyword">from</span> <span class="token string">'axios'</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">fetchArticles</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> data <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> axios <span class="token punctuation">.</span> <span class="token function">get</span> <span class="token punctuation">(</span> <span class="token constant">URL</span> <span class="token punctuation">)</span> <span class="token keyword">return</span> data <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">Articles</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> data <span class="token punctuation">,</span> error <span class="token punctuation">,</span> isError <span class="token punctuation">,</span> isLoading <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useQuery</span> <span class="token punctuation">(</span> <span class="token string">'articles'</span> <span class="token punctuation">,</span> fetchArticles <span class="token punctuation">)</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> isLoading <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token operator"><</span> div <span class="token operator">></span> Loading <span class="token operator">...</span> <span class="token operator"><</span> <span class="token operator">/</span> div <span class="token operator">></span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> isError <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token operator"><</span> div <span class="token operator">></span> Error <span class="token operator">!</span> <span class="token punctuation">{</span> error <span class="token punctuation">.</span> message <span class="token punctuation">}</span> <span class="token operator"><</span> <span class="token operator">/</span> div <span class="token operator">></span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span> div <span class="token operator">></span> <span class="token operator">...</span> <span class="token operator"><</span> <span class="token operator">/</span> div <span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> Articles |
The React Query library has over 1 million Downloads on NPM weekly and over 1.3 thousand stars on GitHub .
3. Reselect
Reselect is a third-party React library for creating Memoization selectors. It is often used with Redux stores and has great features to reduce unnecessary re-rendering.
- Reselect is capable of calculating render data.
- Reselects do not recalculate unless their arguments are changed.
- They can be used as input for other selectors.
Reselect provides an API called createSelector
and it can create Memoization functions. To understand better, let’s look at the example below.
1 2 3 4 5 6 7 8 9 | <span class="token keyword">import</span> <span class="token punctuation">{</span> createSelector <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'reselect'</span> <span class="token operator">...</span> <span class="token keyword">const</span> selectValue <span class="token operator">=</span> <span class="token function">createSelector</span> <span class="token punctuation">(</span> <span class="token parameter">state</span> <span class="token operator">=></span> state <span class="token punctuation">.</span> values <span class="token punctuation">.</span> value1 <span class="token punctuation">,</span> <span class="token parameter">state</span> <span class="token operator">=></span> state <span class="token punctuation">.</span> values <span class="token punctuation">.</span> value2 <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token parameter">value1 <span class="token punctuation">,</span> value2</span> <span class="token punctuation">)</span> <span class="token operator">=></span> value1 <span class="token operator">+</span> value2 <span class="token punctuation">)</span> <span class="token operator">...</span> |
Here, createSelector
takes 2 selectors as input and returns the Memoized version. Selectors will not be recalculated with this Memoized version until the values are changed.
Reselect library has more than 6 million Downloads on NPM weekly and more than 18.4 thousand stars on GitHub .
4. Replace useState() with useRef()
useState()
Hook is widely used in React applications to re-render components when state changes. However, there are cases where we need to track state changes without re-rendering components.
If we use useRef()
Hook then we can track state changes without causing component re-render.
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token keyword">function</span> <span class="token function">App</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span> toggle <span class="token punctuation">,</span> setToggle <span class="token punctuation">]</span> <span class="token operator">=</span> React <span class="token punctuation">.</span> <span class="token function">useState</span> <span class="token punctuation">(</span> <span class="token boolean">false</span> <span class="token punctuation">)</span> <span class="token keyword">const</span> counter <span class="token operator">=</span> React <span class="token punctuation">.</span> <span class="token function">useRef</span> <span class="token punctuation">(</span> <span class="token number">0</span> <span class="token punctuation">)</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> counter <span class="token punctuation">.</span> current <span class="token operator">++</span> <span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span> button onClick <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setToggle</span> <span class="token punctuation">(</span> <span class="token parameter">toggle</span> <span class="token operator">=></span> <span class="token operator">!</span> toggle <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token operator">></span> Click <span class="token operator"><</span> <span class="token operator">/</span> button <span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> ReactDOM <span class="token punctuation">.</span> <span class="token function">render</span> <span class="token punctuation">(</span> <span class="token operator"><</span> React <span class="token punctuation">.</span> StrictMode <span class="token operator">></span> <span class="token operator"><</span> App <span class="token operator">/</span> <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> React <span class="token punctuation">.</span> StrictMode <span class="token operator">></span> <span class="token punctuation">,</span> document <span class="token punctuation">.</span> <span class="token function">getElementById</span> <span class="token punctuation">(</span> <span class="token string">'mydiv'</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> |
The above example has a toggle
that changes the state because the app will re-renders the component every time the value changes. But its counter
value still exists because it is a mutable ref
reference. When we are using same useRef()
, it will only render only. However, if we use useState()
, it will cause 2 impressions for each toggle ( toggle
).
5. Using React Fragments
If you’ve worked with React for quite some time, you know that React requests wrap components with a single parent component. Although it is not directly related to re-render, did you know that it affects overall component render time.
As a workaround, you can also use React Fragments to wrap components and it will reduce the load on the DOM, resulting in faster render times and reduced memory usage.
1 2 3 4 5 6 | <span class="token keyword">const</span> <span class="token function-variable function">App</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span> React <span class="token punctuation">.</span> Fragment <span class="token operator">></span> <span class="token operator"><</span> p <span class="token operator">></span> Hello <span class="token operator"><</span> p <span class="token operator">/</span> <span class="token operator">></span> <span class="token operator"><</span> p <span class="token operator">></span> World <span class="token operator"><</span> p <span class="token operator">/</span> <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> React <span class="token punctuation">.</span> Fragment <span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> |
Roundup
In this article, I discussed 5 different ways to prevent unnecessary re-rendering in React components. Most of these solutions take advantage of caching and you can use the built-in React Hooks or libraries or use 3rd party to implement them.
In addition, these functions will improve application performance and prevent unnecessary re-rendering while reducing memory load.
As always, I hope you enjoyed this article and learned something new.
Thank you and see you in the next posts!
If you find this blog interesting, please give me a like and subscribe to support me. Thank you.