Save wasted renders using React.memo
In mobile friendly app development performance of App really matters. Any one extra render can affect the performance of our application.
Before getting into the solution first lets understand how react renders the changes and what causes the wasted render.
React re-renders the UI whenever state
associated with any component changes. And if this state
is passed as a prop
to components, then each component receiving this state
as a prop
will rendered. This is the how react should work right? So where is the issue? The issue is in JS referential equallity. In Javascript objects
are of non-primitive types. Which means they work on references. Whenever we pass, assign or compare objects, then we are not comparing the values instead we are comparing the references. To make it more clear {}==={}
is false in javascript. Here we are comparing two memory addresses not the value. Read more about it.
In React when we deal with objects we have to be extra attentive about using them in state and props.
Lets understanding this by an example.
To visualize extra render we can use ReactDevTools
. To enable visualization of render we have to turn on this feature. To do so Navigate to React Dev Tools and check the box which says Highlight updates when components render. Make sure it is checked. If you don’t have react-dev-tools
download it from here.
Consider following presentation-al component. It receives an object
pet as a prop and displays the data in UI.
This DumbComponent
is used by App
component to render pet info. In App
component there is a button on click of which we are assigning same information to an object.
Although, we are passing same information on click of button, even though both of the App
and DumbComponent
will be rendered. The Green lines are showing re-rendering.
In class component we have PureComponent
which only re-renders the class component when there is a difference in shallow comparison of Props and state. Which in turn increases the performance of React app by saving few renders. But unfortunately it only work with Class Components
.
For functional component we have React.memo()
. It is a hoc which takes the component as parameter and returns the memoized version of it. React.memo() uses memoization in functional component in order to prevent extra render by proving referential equality.
React.memo()
was introduced in 16.6 , so make sure you are using React v16.6 or later.
If we make our DumbComponent
memoized then we can save this extra rendering. Lets change export default DumbComponent
line to export default React.memo(DumbComponent);
and run our applicaiton.
We can see our DumbComponent
is now not rendering on every click. But our App
component is still re-rendering every time we click on button. Lets fix this as well by adding React.memo()
to App
component.
Now we have prevented the extra re-rendering. We can that even though after multiple clicks on button as passing same object is not triggering the re-rendering.
Note: React.memo() do a shallow comparison of objects.
If we pass nested objects having same data then there will be extra re-render because React.memo() does only shallow comparison not the deep comparison.
We can resolve this by passing out own comparison handler to React.memo().
propsAreEqual
function must return true
if prevProps
and nextProps
are equal.
You may use React.memo() for all Presentational Components, but the component which are going to render for every prop change does not need React.memo()
. As by using React.memo()
we are forcing react to perform one more additional check on passed props
.
Here is the sample code containing example for React.memo()
. https://github.com/rahuulmiishra/reactmemo