3 common mistakes that impede React reconciliation and updating processes
React is one of the fastest JS frameworks out there. Thus it’s down to us to get the most out of it; if we know how to use it in the right way the potential for creating fast applications with it is huge.
Below you can see a comparison between four of the biggest players within javascript frameworks:
Our goal should be, for our components, to have fewer render calls in their lifetime. We can not talk about React Reconciliation process without first understanding the difference between Component
and PureComponent
. As stated in React documentation:
React.PureComponent
is similar toReact.Component
. The difference between them is thatReact.Component
doesn’t implementshouldComponentUpdate()
, butReact.PureComponent
implements it with a shallow prop and state comparison.
why-did-you-render
is a great tool which we’ll use to test our application’s performance. It warns us whenever any of our components re-rendered while its state or props remain unchanged, using a simple console warning.
In this post, we will go through 3 common mistakes that often cause our components to re-render unnecessarily, understand the root causes and finally learn the correct way of implementing our components.
Object Literals
It might seem easier to send a tiny object through props, having a clean shortcode, or to declare our const
in render
method, but compiler sees these as new objects in memory, with different references used in the React Reconciliation process. So each time your component gets updated, a new object is created in the memory and causes the render
method to be run.
In the following example, we will see how unnecessary updating processes take place in each case:
Each time you click on the INCREASE button, React will consider style={{width: 100%}}
to be a new value, which when passed to MyList
updates the big list. Now imagine the huge impact that would have on large scale applications.
Correct Way:
Anonymous functions
Writing an anonymous function while passing those props might seem fast and requiring fewer lines but same as object literals, to React, an anonymous function is a new closure, a new object in memory with a different reference.
In the following example, we will see how unnecessary re-renderings happen by using those nasty anonymous functions:
Correct Way:
Using too many props or spreading unnecessary props
As we develop a component, there will come a time that we will want to add different properties to make our component even more customizable. By adding several styling properties, we can expand the wide variety of data provided to a certain component. Though some of these scenarios are inevitable, in most cases by making small tweaks in the architecture of your component, you can achieve a performance boost by breaking down your component into smaller pieces (either horizontal or vertical fragmentation) avoiding unnecessary re-rendering.
By doing this, your main component, which has to look after a handful of properties, now lets its child components take care of each updating process, meaning a small part of your application would re-render.
In the following example, we can see how passing extraneous properties down to a component might cause an unneeded reconciliation process to take place by triggering an unnecessary update on each prop change:
The correct way to avoid these mistakes is to define each component’s responsibility before even starting to code and only send those props which are necessary to your child components:
When it comes to medium or large applications, the most appropriate solution for this issue would be to use a state-management framework such as Redux (or any other Flux architecture). A child only has to receive props which are contextual to it (if it’s a part of the child context). Other than that, the child component can use the store; this way we would define each component’s responsibility by its context.
For example, a list of friend requests on a social media app (let’s call it RequestsList component). Our RequestsList would contain a list of requests showing the state of each request (accepted or rejected), a short welcome message and the user information such as name and user avatar. While iterating over each Request component, our RequestsList should not care about user information (name and avatar), for these properties could be retrieved from the store directly by Request component.
This is where a state management framework such as Redux comes into play. By providing a global store in your app, it enables the shareable data which several parts of your app might need and helps to avoid sending props to many layers of child components. In React, data provided to each component can be used internally, like user information in our `RequestList` example, which was sent through props to Request component. While designing your app, you might want to use part of your data in more than component; a user avatar can be used in the list of requests, user profile pages or in one or many posts.
Further readings: