header-digital-transformation

A hub for technology and sourcing thought leadership

About us

React applications - when performance matters

04 Oct 2019
by Pavel Petrov

App performance matter

There are many React tutorials on the Internet. A lot of people go through these tutorials and start writing React applications very quickly. And most times this is not a problem. That’s the nature of React. It doesn’t have much boilerplate code and it’s easy to use as long as you have fundamental JavaScript knowledge. But what happens when the application scales and its components get more and more complex? This is where performance becomes a very important part of the project. The following article aims to show how some small tricks could improve the performance of your application big time! Have in mind while reading it, that the optimizations are valid for ReactJS v15.6 up to now.

In a large application state updates and events “fly” everywhere, thus causing a huge amount of re-rendered components. Sometimes this might be caused even when nothing has changed in the component, so rendering visually the same UI element as before is a total waste of resources. Therefore, the first thing we need to get rid of are those wasted renders. So, how do we do that?

Eliminate wasted renders

Well, if the first step is eliminating unnecessary renders, then step zero is identifying them. Sounds fair, doesn’t it? One good approach is to use Facebook’s official dev tool for Chrome called React Developer Tools.

I have created a fairly simple application to demonstrate how you can use it. Now, it may seem too simple for real world usage, but the following optimization can always be applied. The application has “Main” and “Profile” components. The “Main” component is the parent of “Profile” and is used to render the title of the page and a button that changes that title. “Profile” renders the name of a user and his age. The purpose is to show you how the “Profile” component is re-rendered when the title has been changed. Below is a snippet of its implementation and a short demo of using React Dev Tools.

Profile component
Profile Component

See a demo here!

You can see that changing the “Main” component’s title caused “Profile” to render again. But nothing actually changed there! Why did “Profile” get updated? It happened because “Profile” is a child component of “Main” and its re-rendering passed the props to “Profile” again. Although they did not change, React was not aware of that, hence “Profile’s” render method was invoked again. There are two ways of telling React not to do that:

1) Use “PureComponent” instead of “Component”

Under the hood, React uses the so-called lifecycle method shouldComponentUpdate. This method compares the previous and current props and state. If there are no differences, the render method is not triggered.

Let us have a look at how the application behaves with this minor change.

Profile PureComponent
Profile PureComponent

See a demo here!

Good, now the “Profile” component renders only once when it is initially loaded. However, you should have in mind that “PureComponent” does a shallow comparison only. Meaning that, if you were to pass a complex data structure, it might result in unwanted behavior of the Render method. Value types such as strings and numbers are compared by value, while reference types such as objects and arrays are compared by reference.

In this case, it is better to ...

2) use Component and implement shouldComponentUpdate yourself
, making sure that your component is re-rendered only when needed. An important side note heredo not overuse this lifecycle! Only use it when you are very confident that the component should not re-render under some circumstances, otherwise you are just introducing extra complexity. Even the guys from Facebook recommend that in React’s own documentation.

Avoid passing callback functions as props

Avoid passing callback functions as props

Alright! We optimized our app by eliminating renders we don’t need. Great! A known fact is that whenever props in a given component change, a re-render occurs. Therefore, if you pass a function declaration as a prop value, a new instance of that function will be created every single time the component is re-rendered. This is because JavaScript has no way of accessing the previously declared function, since it is an anonymous one. Eventually, the old function instance would be cleared out of the memory and unnecessary resources will be spent doing that. Instead, you could declare the function as a method of your class component, bind it in the constructor and then pass the reference.

To say it in code, instead of doing this:

A new instance of function on every render
Creating a new instance of the function on every render

... do that: 

A reference to an instance of the function
Passing a reference to an instance of the function

Of course, this applies to all objects that are passed as props. If the objects won’t change, it’s better to assign them to your class component’s this and pass the reference instead.

Split Your Code into Chunks

Usually, the application bundling ends up producing a single file. This is a problem because as the application grows larger and larger, so does the bundled file.

Request to the server
 Visiting the site will make a request to the server for the single large bundled JS file

One approach here would be to separate your app into smaller chunks using react-router. This will add routing to your application, therefore, components will be loaded only when a request to the component’s specific route has been made.

Visiting contacts or profile
Visiting /contacts or /profile will only load "Contacts" and "Profile" related code respectively

Another approach is to use Code-Splitting. This is a feature supported by most bundlers such as Webpack and Browserify, which can create multiple bundles that can be dynamically loaded at runtime. Essentially, the above-mentioned react-router does virtually the same behind the scenes, with the difference that it allows the developer to specify which chunk of code to be loaded at a specific route.

The official documentation of React sums it up perfectly:

Code-splitting your app can help you “lazy-load” just the things that are currently needed by the user, which can dramatically improve the performance of your app. While you haven’t reduced the overall amount of code in your app, you’ve avoided loading code that the user may never need and reduced the amount of code needed during the initial load.

To use code-splitting you can simply change the normal import() with its dynamic syntax:

Normal and dynamic import
Normal and dynamic import

When Webpack comes across this syntax, it automatically starts code-splitting your app.

An important side note here is that the dynamic import() syntax is not yet part of the ECMAScript standard, but it should be accepted in the near future.

Use the Production Build

One last thing we need to check is to make sure we use the production build when deploying to production. This will minify and uglify the JS files and make their sizes a lot smaller. If you’ve used create-react-app for bootstrapping your application, use the command npm run build to run a production build.

Conclusion

We’ve covered several points for improving React’s performance:

  • Pinpoint wasted renders and eliminate them if possible;
  • Pass functions/objects by reference;
  • Use code splitting with react-router or dynamic imports;
  • Use the production build when releasing your application.

These can be used as a checklist when needed or just when you want to reach perfection! In the end, it never hurts to do your best when it comes to optimizing performance!

Happy coding! 😊

Pavel is a Software Consultant at Accedia. Eager to meet new challenges, he constantly strives for code quality and aims to apply the best practices in his projects.

Leave a comment