![](http://habrastorage.org/getpro/habr/avatars/085/df8/392/085df839215d4764ba156a92b3272a7e.jpg)
Improving React Component Functionality with React.memo ()
- Transfer
We present to you a translation of the article by Chidume Nnamdi, which was published on blog.bitsrc.io. If you want to learn how to avoid unnecessary rendering and how new tools are useful in React, welcome to cat.
![](https://habrastorage.org/webt/pd/cr/7a/pdcr7arl6hgkxg17v5c4laoxsj8.jpeg)
The React.js team is working hard to make React run as fast as possible. To enable developers to speed up their React applications, the following tools have been added to it:
In this article, we will consider, among others, another optimization tool added in React v16.6 to speed up component functions - React.memo .
Tip: Use Bit to install and share React components. Use your components to build new applications and share them with the team to speed things up. Give it a try!
![](https://habrastorage.org/webt/uk/nn/k8/uknnk8ugyblbcsges3q5aag8n3m.gif)
In React, each component corresponds to a view unit. Components also have states. When the state value changes due to user actions, the component realizes that redrawing is needed. The React component can be redrawn any number of times. In some cases, this is necessary, but most often you can do without a renderer, especially since it greatly slows down the application.
Consider the following component:
The initial value of the {count: 0} state is 0. If you click the Click me button, the count state will become 1. On our screen, 0 will also change to 1. But if we click the button again, problems begin: the component should not be redrawn, because it the condition has not changed. The counter value “to” is 1, the new value is also one, which means that there is no need to update the DOM.
To see the update of our TestC, in which the same state is set twice, I added two life cycle methods. React starts the componentWillUpdate cycle when the component is updated / redrawn due to a state change. The componentdidUpdate React cycle starts when a component renders successfully.
If we launch the component in the browser and try to click the Click me button several times, we get the following result:
![](https://habrastorage.org/webt/qj/l9/zx/qjl9zx25xiry_bzjrwasb9t4b5k.png)
Repeating the componentWillUpdate entry in our console indicates that the component is redrawn even when the state does not change. This is an extra render.
The shouldComponentUpdate lifecycle hook will help avoid unnecessary rendering in React components.
React launches the shouldComponentUpdate method at the beginning of component rendering and receives a green light from this method to continue the process or a signal that the process is inhibited .
Let our shouldComponentUpdate look like this:
So we allow React to render the component because the return value
Suppose we write the following:
In this case, we forbid React to render the component, because the value is returned
From the above it follows that for rendering the component we need the value to return
We added a shouldComponentUpdate hook to the TestC component. Now the value
If we test the code in a browser, we will see a familiar result:
![](https://habrastorage.org/webt/jp/wd/2x/jpwd2xhiz5zckb5f2c-xwosbife.png)
But by clicking on the button
![](https://habrastorage.org/webt/gy/xc/ir/gyxcir1kjjyki18hzqxdfz5hzeu.png)
![](https://habrastorage.org/webt/pi/qg/ix/piqgixsafppm6jygqftfm8nkpyq.png)
This value can be changed. Click on the counter text, type 2 and press Enter.
![](https://habrastorage.org/webt/v3/4m/tl/v34mtl_unwz6gmkip2kxw_4a1km.png)
The state of count will change, and in the console we will see:
![](https://habrastorage.org/webt/ql/3y/_i/ql3y_ijc3qwx9byxo_lu8ckbg-g.png)
The previous value was 1, and the new one was 2, so a redraw was required.
Let's move on to the Pure Component .
Pure Component appeared in React in version v15.5. It is used to compare default values (
Add a PureComponent to the TestC component.
As you can see, we made
Rebooting the browser to test the new solution, and clicking on the button
![](https://habrastorage.org/webt/jp/wd/2x/jpwd2xhiz5zckb5f2c-xwosbife.png)
![](https://habrastorage.org/webt/gy/xc/ir/gyxcir1kjjyki18hzqxdfz5hzeu.png)
As you can see, only one entry appeared in the console
After seeing how to work in React with redrawing in the component classes of ES6, we move on to the component functions. How to achieve the same results with them?
We already know how to optimize work with classes using the Pure Component and the life cycle method
It is important to remember that component functions, unlike component classes, have no state (although now that hooks have appeared
We turn our component class ES6 TestC into a component function.
After rendering in the console, we see a record
![](https://habrastorage.org/webt/zl/ul/q4/zlulq4t7iokqfn9my1s9yka6v_w.png)
Open DevTools and click on the React tab. Here we will try to change the value of the properties of the TestC component. Select TestC, and the counter properties with all the properties and values of TestC will open on the right. We see only the counter with the current value of 5.
Click on the number 5 to change the value. An input window will appear instead.
![](https://habrastorage.org/webt/1h/u-/31/1hu-31ov7pulpn2iuqatr667rns.png)
If we change the numerical value and press Enter, the properties of the component will change according to the value we entered. Suppose at 45.
![](https://habrastorage.org/webt/bn/9t/yx/bn9tyxzi3bznqpx_6onqz2athra.png)
Go to the Console tab.
![](https://habrastorage.org/webt/1m/8a/k8/1m8ak8oggdsmsahkqbg8npptrau.png)
The TestC component was redrawn because the previous value of 5 changed to the current one - 45. Go back to the React tab and change the value to 45, then go back to Console.
![](https://habrastorage.org/webt/ea/mu/vy/eamuvycxua6dksm8yp_o2b0bcym.png)
As you can see, the component is redrawn again, although the previous and new values are the same. :(
How to manage the renderer?
How to work with React.memo (...)?
Pretty simple. Say we have a component function.
We only need to pass FuncComponent as an argument to the React.memo function.
React.memo returns
Apply this to the TestC function component.
Open a browser and download the application. Open DevTools and go to the React tab. Select
If in the block on the right we change the properties of the counter to 89, the application will be redrawn.
![](https://habrastorage.org/webt/kf/tl/ms/kftlmsn1bznnmh9loxbedc_acqi.png)
If we change the value to the previous one, 89, then ...
![](https://habrastorage.org/webt/j4/ak/tq/j4aktqq4qfwkizulxk2h-em4ism.png)
There will be no redrawing!
Glory to React.memo (...)! :)
Without application
If you have any questions about the article or any additional information, changes or objections, do not hesitate to write me comments, emails or private messages.
Thanks!
![](https://habrastorage.org/webt/pd/cr/7a/pdcr7arl6hgkxg17v5c4laoxsj8.jpeg)
The React.js team is working hard to make React run as fast as possible. To enable developers to speed up their React applications, the following tools have been added to it:
- React.lazy and Suspense for delayed component loading;
- Pure component
- lifecycle hooks shouldComponentUpdate (...) {...}.
In this article, we will consider, among others, another optimization tool added in React v16.6 to speed up component functions - React.memo .
Tip: Use Bit to install and share React components. Use your components to build new applications and share them with the team to speed things up. Give it a try!
![](https://habrastorage.org/webt/uk/nn/k8/uknnk8ugyblbcsges3q5aag8n3m.gif)
Extra render
In React, each component corresponds to a view unit. Components also have states. When the state value changes due to user actions, the component realizes that redrawing is needed. The React component can be redrawn any number of times. In some cases, this is necessary, but most often you can do without a renderer, especially since it greatly slows down the application.
Consider the following component:
import React from 'react';
class TestC extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
}
}
componentWillUpdate(nextProps, nextState) {
console.log('componentWillUpdate')
}
componentDidUpdate(prevProps, prevState) {
console.log('componentDidUpdate')
}
render() {
return (
{this.state.count}
);
}
}
export default TestC;
The initial value of the {count: 0} state is 0. If you click the Click me button, the count state will become 1. On our screen, 0 will also change to 1. But if we click the button again, problems begin: the component should not be redrawn, because it the condition has not changed. The counter value “to” is 1, the new value is also one, which means that there is no need to update the DOM.
To see the update of our TestC, in which the same state is set twice, I added two life cycle methods. React starts the componentWillUpdate cycle when the component is updated / redrawn due to a state change. The componentdidUpdate React cycle starts when a component renders successfully.
If we launch the component in the browser and try to click the Click me button several times, we get the following result:
![](https://habrastorage.org/webt/qj/l9/zx/qjl9zx25xiry_bzjrwasb9t4b5k.png)
Repeating the componentWillUpdate entry in our console indicates that the component is redrawn even when the state does not change. This is an extra render.
Pure Component / shouldComponentUpdate
The shouldComponentUpdate lifecycle hook will help avoid unnecessary rendering in React components.
React launches the shouldComponentUpdate method at the beginning of component rendering and receives a green light from this method to continue the process or a signal that the process is inhibited .
Let our shouldComponentUpdate look like this:
shouldComponentUpdate(nextProps, nextState) {
return true
}
nextProps
: the next valueprops
that the component will receive;nextState
: The next valuestate
that the component will receive.
So we allow React to render the component because the return value
true
. Suppose we write the following:
shouldComponentUpdate(nextProps, nextState) {
return false
}
In this case, we forbid React to render the component, because the value is returned
false
. From the above it follows that for rendering the component we need the value to return
true
. Now we can rewrite the TestC component as follows:import React from 'react';
class TestC extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
}
}
componentWillUpdate(nextProps, nextState) {
console.log('componentWillUpdate')
}
componentDidUpdate(prevProps, prevState) {
console.log('componentDidUpdate')
}
shouldComponentUpdate(nextProps, nextState) {
if (this.state.count === nextState.count) {
return false
}
return true
}
render() {
return (
{ this.state.count }
);
}
}
export default TestC;
We added a shouldComponentUpdate hook to the TestC component. Now the value
count
in the object of the current state is this.state.count
compared with the value count
in the object of the next state nextState.count
. If they are equal ===
, redrawing does not occur and the value is returned false
. If they are not equal, a value is returned true
and a renderer is launched to display the new value. If we test the code in a browser, we will see a familiar result:
![](https://habrastorage.org/webt/jp/wd/2x/jpwd2xhiz5zckb5f2c-xwosbife.png)
But by clicking on the button
Click Me
several times, all we see will be the following (displayed only once!):
You can change the state of the TestC component in the React DevTools tab. Click on the React tab, select TestC on the right, and you will see the counter status value:componentWillUpdate
componentDidUpdate
![](https://habrastorage.org/webt/gy/xc/ir/gyxcir1kjjyki18hzqxdfz5hzeu.png)
![](https://habrastorage.org/webt/pi/qg/ix/piqgixsafppm6jygqftfm8nkpyq.png)
This value can be changed. Click on the counter text, type 2 and press Enter.
![](https://habrastorage.org/webt/v3/4m/tl/v34mtl_unwz6gmkip2kxw_4a1km.png)
The state of count will change, and in the console we will see:
componentWillUpdate
componentDidUpdate
componentWillUpdate
componentDidUpdate
![](https://habrastorage.org/webt/ql/3y/_i/ql3y_ijc3qwx9byxo_lu8ckbg-g.png)
The previous value was 1, and the new one was 2, so a redraw was required.
Let's move on to the Pure Component .
Pure Component appeared in React in version v15.5. It is used to compare default values (
change detection
). Using extend React.PureComponent
, you can not add a life cycle method shouldComponentUpdate
to components: change tracking happens by itself. Add a PureComponent to the TestC component.
import React from 'react';
class TestC extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
count: 0
}
}
componentWillUpdate(nextProps, nextState) {
console.log('componentWillUpdate')
}
componentDidUpdate(prevProps, prevState) {
console.log('componentDidUpdate')
}
/*shouldComponentUpdate(nextProps, nextState) {
if (this.state.count === nextState.count) {
return false
}
return true
}*/
render() {
return (
{ this.state.count }
);
}
}
export default TestC;
As you can see, we made
shouldComponentUpdate
a comment. We no longer need it: it does all the work React.PureComponent
. Rebooting the browser to test the new solution, and clicking on the button
Click Me
several times, we get: ![](https://habrastorage.org/webt/jp/wd/2x/jpwd2xhiz5zckb5f2c-xwosbife.png)
![](https://habrastorage.org/webt/gy/xc/ir/gyxcir1kjjyki18hzqxdfz5hzeu.png)
As you can see, only one entry appeared in the console
component*Update
. After seeing how to work in React with redrawing in the component classes of ES6, we move on to the component functions. How to achieve the same results with them?
Function Components
We already know how to optimize work with classes using the Pure Component and the life cycle method
shouldComponentUpdate
. No one argues that class components are the main components of React, but you can use functions as components.function TestC(props) {
return (
I am a functional component
)
}
It is important to remember that component functions, unlike component classes, have no state (although now that hooks have appeared
useState
, this can be argued with), which means that we cannot configure their redrawing. The life cycle methods that we used while working with classes are not available to us here. If we can add lifecycle hooks to function components, we can add a method shouldComponentUpdate
to tell React that a function renderer is needed. (Perhaps, in the last sentence, the author made a factual mistake. - Approx. Ed.) And, of course, we cannot use it extend React.PureComponent
. We turn our component class ES6 TestC into a component function.
import React from 'react';
const TestC = (props) => {
console.log(`Rendering TestC :` props)
return (
{props.count}
)
}
export default TestC;
// App.js
After rendering in the console, we see a record
Rendering TestC :5
. ![](https://habrastorage.org/webt/zl/ul/q4/zlulq4t7iokqfn9my1s9yka6v_w.png)
Open DevTools and click on the React tab. Here we will try to change the value of the properties of the TestC component. Select TestC, and the counter properties with all the properties and values of TestC will open on the right. We see only the counter with the current value of 5.
Click on the number 5 to change the value. An input window will appear instead.
![](https://habrastorage.org/webt/1h/u-/31/1hu-31ov7pulpn2iuqatr667rns.png)
If we change the numerical value and press Enter, the properties of the component will change according to the value we entered. Suppose at 45.
![](https://habrastorage.org/webt/bn/9t/yx/bn9tyxzi3bznqpx_6onqz2athra.png)
Go to the Console tab.
![](https://habrastorage.org/webt/1m/8a/k8/1m8ak8oggdsmsahkqbg8npptrau.png)
The TestC component was redrawn because the previous value of 5 changed to the current one - 45. Go back to the React tab and change the value to 45, then go back to Console.
![](https://habrastorage.org/webt/ea/mu/vy/eamuvycxua6dksm8yp_o2b0bcym.png)
As you can see, the component is redrawn again, although the previous and new values are the same. :(
How to manage the renderer?
Solution: React.memo ()
React.memo()
- New in React v16.6. The principle of its operation is similar to the principle of work React.PureComponent
: assistance in managing the redrawing of component functions. React.memo(...)
for class components, this is React.PureComponent
for function components. How to work with React.memo (...)?
Pretty simple. Say we have a component function.
const Funcomponent = ()=> {
return (
Hiya!! I am a Funtional component
)
}
We only need to pass FuncComponent as an argument to the React.memo function.
const Funcomponent = ()=> {
return (
Hiya!! I am a Funtional component
)
}
const MemodFuncComponent = React.memo(FunComponent)
React.memo returns
purified MemodFuncComponent
. This is what we will draw in the JSX markup. When the properties and state of a component change, React compares the previous and current properties and states of the component. And only if they are not identical, the component function is redrawn. Apply this to the TestC function component.
let TestC = (props) => { console.log('Rendering TestC :', props) return (
{ props.count } ) } TestC = React.memo(TestC);
Open a browser and download the application. Open DevTools and go to the React tab. Select
. If in the block on the right we change the properties of the counter to 89, the application will be redrawn.
![](https://habrastorage.org/webt/kf/tl/ms/kftlmsn1bznnmh9loxbedc_acqi.png)
If we change the value to the previous one, 89, then ...
![](https://habrastorage.org/webt/j4/ak/tq/j4aktqq4qfwkizulxk2h-em4ism.png)
There will be no redrawing!
Glory to React.memo (...)! :)
Without application
React.memo(...)
in our first example, the TestC component function is redrawn even when the previous value changes to the identical one. Now, thanks React.memo(...)
, we can avoid unnecessary rendering of component-functions.Conclusion
- Let's go through the list?
React.PureComponent
- silver;React.memo(...)
- gold;React.PureComponent
works with ES6 classes;React.memo(...)
works with functions;React.PureComponent
optimizes the redrawing of ES6 classes;React.memo(...)
optimizes redrawing functions;- feature optimization is a terrific idea;
React
will never be the same again.
If you have any questions about the article or any additional information, changes or objections, do not hesitate to write me comments, emails or private messages.
Thanks!