Learn about React.memo (), useMemo (), and useCallback ()

Tram Ho

With the development of the internet world today, the website elements are becoming more and more complex.

In web applications built with ReactJS, rerendering many times complex components will greatly affect the performance of the web application, thereby affecting the user experience.

Users like websites with fast and responsive UI. Low response latency below 100 milliseconds creates instant feel. If the delay from 100 – 300 milliseconds will make users feel clearly about the slowdown of the website.

To improve web app performance, React v16.6 release React provides a HOC called React.memo (). When React.memo () surrounds a component, React will remember the render results and ignore unnecessary rendering, in order to optimize the performance of functional components rendering.

So what is React.memo ()? How to use it? What cases should and should not take it? Let’s start to find out!

1. What is React.memo ()?

As you all know, Functional Component, or Class Component return false in shouldComponentUpdate, that component will not be re-rendered when the tree changes, it only changes when the passed prop changes.

React.memo () works exactly like React.PureComponent (), but it’s a function component instead of a class like PureComponent. React.memo is a higher order component, used to wrap components. Using React.memo (), React will skip the re-rendering of the component and use the last rendered result if your component renders the same result as the same props.

Take a specific example as follows: The component’s background will change to red if the user enters an even number, which is green if the user enters an odd number.

The ColoredSquare component will always be re-rendered every time a user changes a price on the input, no matter what value it is. To improve the performance of the application, we need to treat the component to render again only if the value changes from even to odd or even to even. We can use React.memo as follows:

The second argument passed to React.memo will be the function used by React to determine whether to re-render based on a change of props. If the return value of the function is true, it means that React will not re-render this component, but reuse the previously rendered result and vice versa, if it returns false, React will re-render this component.

My little bit of comparison between React.memo () vs shouldComponentUpdate ()

Same:

Different:

2. When to use React.memo ()

  1. First of all, your component must be a functional component.
  2. Your component is frequently re-rendered.
  3. If your component is always re-rendered even though the prop doesn’t change.
  4. Your component contains a large amount of computational logic and UI like Chart, Canvas, 3D library….

Regular re-rendering components with the same prop. An extremely common case of React code is the following. MovieViewsRealtime shows the number of views of a movie, with realtime updated data.

App will connect to the server and update prop views

Each time the prop views are updated with a new number, MovieViewsRealtime will re-render. This causes the Movie to also re-reder even though the title and releaseDate have not changed.

In this case we will apply React.memo () to restrict re-rendering on the Movie component

As long as title and releaseDate don’t change, React will skip MemoizedMovie re-render. This will improve the performance of the MovieViewsRealtime component.

3. When to avoid using React.memo ()

  1. If your component isn’t re-rendered even though the prop hasn’t changed, chances are you don’t need React.memo ().

Use the following rule of thumb: don’t use memoization if you can’t quantify performance achieved.

  1. Performance-related changes applied incorrectly can even harm performance. Use React.memo () wisely.

Possibly, class-based components on React.memo () are not desirable. Extend PureComponent class or declare a custom implementation of the shouldComponentUpdate () method if you need to memorize class-based components.

  1. Your component is the class component
  2. Your component has been memoed by another HOC, for example connect () of Redux.

There are some people who think their props components change frequently, so they don’t need to use React.memo (). That’s also true, but in my personal opinion when a code in a React app is large, your re-rendering of the component is also affected by the state of the parent component, not just by props the prop that the child component receives. to enter. So there will definitely be useless re-renderings, more or less. So I will use React.memo () to make sure.

4.useMemo ()

The name looks the same, but not the same, if React.memo is a HOC to remember a function component, useMemo is a helper-like function that allows you to specify: to store the results of which function and what values ​​to do for it. change that result.

useMemo focuses on avoiding repetitive heavy computational logic.

Specifically, it returns a value (the result returned from the execution, running the function fn that you pass in corresponding to the first parameter).

If one of the dependencies changes, the computation will be run again, thus returning a new value. On the contrary, if realizing that the value of the other dependencies is constant, useMemo immediately returns the previous results without recalculating, thereby avoiding a large amount of work, helping performance.

In addition, taking advantage of the feature that returns the previous value when the dependencies are not changed, we will also avoid creating unnecessary objects (old objects will be returned), which helps avoid unnecessary re-rendering.

4. 1 Avoid heavy calculations

When not using useMemo ()

Write like this, every time you press the button to increase the count variable, componentA will re-render, and the getArray function will run again, taking 2 seconds to get the results and render to the screen.

When using useMemo ()

Now, even if you press the button and increase the count variable, the getArray function immediately returns the previous result value without spending 2 seconds of computation. Notice that getArray is no longer a function caller, because useMemo itself has run the function we pass in, our dev’s job is to recognize a memoized value only.

4.2 Avoid re-rendering

When not using useMemo ()

Write like this, every time ComponentA re-render, getStyle function will create a new object and pass to ComponentB, causing ComponentB to be re-rendered (even though React.memo was used).

When using useMemo ()

Now, when using useMemo for getStyle function, (note that getStyle no longer calls the function, useMemo has executed the function we passed in, we only get the result – a memoized value) on re-attempts After rendering of ComponentA, the old style object will be returned instead of creating a new one -> React.memo in ComponentB noticed the received prop has no change -> does not re-render.

5.useCallback ()

UseCallback focuses on solving performance problems, since callback functions created in functional components that are passed down to child components are always created, causing children to always be re-rendered.

useCallback returns a function (the function you pass in with the first parameter), this callback function will be recreated when one of the dependencies changes. If the dependencies do not change, the function returns will be the previous function -> that is, the function passes down the child component that is not newly created, equivalent to no newly created object -> the child component is not re-rendered.

5.1 Avoid re-rendering in child components

When not using useCallback

Write this, each time the Parent component re-render, the onChangeHandler callback will be created a new one and passed down to the Pure child component. Even though the component uses React.memo, it is still re-rendered.

When using useCallback

Thanks to the use of useCallback, now each time the Parent component re-renders, the onChangeHanlder function will no longer always be newly created, but will only be created when its depencency is variable a. The function is not newly created -> the object is not newly created -> the child component received is also not re-rendered. Great!

6. React.memo () with useCallback ()

Now we have the following example: Component Logout takes a callback prop of onLogout, and encapsulates React.memo ().

A component that receives a callback should be handled with the memo technique. Each time the parent component re-renders it creates a new instance of the callback.

At this point, even though the username has not changed, MemoizedLogout is still rendering again because it receives a new instance of the onLogout callback.

React.memo () isn’t working anymore at this point.

To fix this, we use a React hook called useCallback () to prevent the creation of a new callback instance between each render.

useCallback (() => cookies.clear (‘session’), [cookies]) always return an instance function, as long as cookies don’t change. Now we have fixed the above problem.

6.useCallback () <==> useMemo ()

As mentioned above, useMemo will execute the passed function and return the result. If cleverly, return the function as a result, then useMemo will have the same role and effect as useCallback.

summary

React.memo () is a great tool for remembering functional components. When used correctly, it will help you increase performance and UX significantly. Be wary of the callback function too, always making sure that the instance of the callback is always the same between re-render.

My article here is the end. Hope it helps you to decode the two rather confusing hooks in React, useCallback and useMemo, and at the same time help us understand the problems of re-rendering in the functional component world and somewhat for you in the process. study as well as work. I have just learned about React, so the article is also hard to avoid mistakes, hope everyone sympathizes and hopes for everyone’s comments to make the article more complete.

Share the news now

Source : Viblo