How to Optimize React Hooks Performance – Optimize performance when using React Hooks

Tram Ho

Original article:

Since version 16.8, React introduced a new feature called React Hooks. In short, React Hook is an upgraded version of function component, allowing function component to use features that previously only component class had such as life cycle hooks, state.

But as in the swordplay movie or a sentence, the more power the sword has, the more difficult it is to control , let’s find out how to control this React Hooks in the most effective way.

Getting started

First, create a completely new project using the Create React App

Then, rewrite the entire App.js file as follows:

In the App component, we have an input tag, with the value controlled by the value variable generated by the useState hook. At the same time, we also show the Counter component imported from ./Counter.js , now let’s create the Counter component:

In this Counter component, we will have a counter state, which will increase each time we press the Increase Counter button, and a ref renders to “keep track” of the number of times our component is re-rendered, in other words. is the pile inside the return being run again.

Talking more about using useRef here, there will be many of you as well as me when first seeing this useRef, will surely wonder why useRef. So the answer is we want to calculate the number of re-renders of the component, and useRef gives us exactly what we need. Because when changing the value of .current of ref, it will not trigger the re-render. Can you read more about this feature of useRef at useRef and Is there something like instance variables?

The unnecessary rerender

Now that you try yarn start to run the application, you will see that each time you press the “Increase Counter” button, the number of counters will be equal to the number of render times. This means that the Counter component will be re-rendered (in other words, the jsx pile in the return run again) every time the state changes.

( NOTE : Remember to remove React.StrictMode from the index.js file, as it will cause the component to render twice )

But, when we type in App component input, we see that the number of renders still increases. This means that the Counter component will also re-render every time the state of the input cell in App componnet changes, this is not necessary because nothing we want to change inside the Counter component.

Reruning the code in the Counter component is not necessary, so how can we avoid this?

Memoizing components

Since version 16.6 , we have added React.memo which is similar to PureComponent or shouldComponentUpdate on the component class, but React.memo is for function component. These fancy stuffs are intended primarily for optimize performance, meaning it helps to reduce the number of renderings. That means it only renders when the input prop changes, but if the same, it will “bail out”. Speaking of which, you can study more about the mechanism by which React determines which is the same, what is different, that is, the algorithm it uses to compare props to determine if there is a change.

Now let’s try React.memo to wrap our Counter .

Simple, easy to use! Now try to open our app, and we will see that the Counter component won’t re-render every time we enter the input box.

When we pass a prop into the memoried component, this memoried component checks to see if the prop has changed to decide whether to re-render the component or not. To test this feature, try passing a prop to the Counter component.

Here, we are passing greeting prop to the Counter component. If you run the app again, it will be the same as it was just now. Because the memoried component will only update again when the prop changes.

Memoizing functions

React.memo is awesome, but it also has its downsides. It will work fine with data types like string, number, boolean. As for objects and functions, it’s not smart enough to correctly check for changes.

Here we are passing to Counter two new prop , a function and an object. And at this point, every time we enter the App component input box, our Counter component re-renders. This means that, for each run, the props going to the Counter component are a different function and an object. Props to change so the component re-render.

To solve this problem, we can use useCallback , to memoize the function before passing down to the Counter component. The memozied version of the function will only change when one of the dependencies changes. Let’s fix the code in App.js as follows:

This method is very useful when we have more than one state hook. The memoized function will only be run again when the chosen state is changed. To illustrate this, let’s add one more input box:

Now, when we click on the new input box, the Counter component will not re-render, because we have shown in the [] dependencies that it only depends on the value value , it is only rerun when the That value changes, while other values ​​change, let alone.

Memoizing objects

By now, we already know how to memoize functions, but there’s one more thing we should know about momoizing.

Currently, our Counter component is still re-rendered every time the state changes. That’s because the myObject prop hasn’t been memoized yet. We can use useMemo to memoize all values ​​(including objects) by passing a “create” function and an array of dependencies . The calculated value will only be recalculated when one of the dependencies changes (just like the useCallback above).


By applying these methods, we will be able to passs props into a memozied component in the most optimal way.

Share the news now

Source : Viblo