React uses many techniques internally to minimize the number of DOM operations that are required to update UI.

However any application, whether developed in React or any other front-end framework, it’s performance will degrade eventually.

Developers must understand how React works and its component life-cycle. If we are able to understand these concepts properly, we can gain lot of performance improvements. This can be done by measuring and optimizing, HOW and WHEN, of components rendering.

Other than these, there are many other ways by which we can speed up a React application. Based on my team’s experience, I am writing down a few points that I can think will be helpful for optimizations.

Please note that this list is not exhaustive and it covers only a few aspects. There are many other techniques also which can be used to improve performance.

Use the Production Build

It is a very basic technique and I believe everyone is doing this. However, it is worth mentioning. We should be using a minified production build while deploying our app to users.

Bundling and Minification

For any React SPA, we can bundle all our JavaScript code in a single minified file. This is fine as long as our application is small.

However, as soon as it starts growing, managing all JS code in one file becomes tedious and code will be ugly to understand. Also sending this one big file to the browser in itself will be a very time-consuming process. Hence we need to use some mechanism to split our app into multiple files and deliver them to the browser when needed.

If we are using Webpack, we can leverage its code splitting capabilities to convert our application code to multiple ‘chunks’ of file.

There are two types of splitting: Resource Splitting and On-Demand code splitting.

With Resource Splitting, we can split resource content into multiple files. For example, using CommonsChunkPlugin, we can extract common code (such as all external libraries) into a “chunk” file of its own.

Using ExtractTextWebpackPlugin, you can extract all CSS code into a separate CSS file.
This kind of splitting will help in two ways.

  • It helps the browser to cache those less frequently changing resources.
  • It will also help the browser to take advantage of parallel downloading to potentially reduce the load time.

Another noteworthy feature of Webpack is On-Demand code splitting. We can use it to split code into chunks that can be loaded on-demand.

This can keep the initial download small, reducing the time it takes to load the app. The browser can then download other chunks of code on-demand when needed by the application.

Don’t use an array index as the key when using .map()

Suppose we want to render a list and if we don’t set any key, we will see below warning in the console.

Warning: Each child in an array or iterator should have a unique “key” prop.

To fix this, many times we simply pass in the loop’s index value as the key value of the child element.

{todos.map((todo, index) =>
<Todo
{...todo}
key={index}
/>
)}

It looks clean and gets the job done. It gets rid of the warning, which was the real problem here, right? However, the real danger lies ahead.

It may break our application and display wrong data too…!

Index as a key is an Anti-Pattern.

Why, because a key is the only thing React uses to identify DOM elements. When we push or remove any item from the list and if the key is the same as before, React assumes that the DOM element represents the same component. But that is no longer true since the update happened.

It’s always advisable to use a unique property as a key, or if it don’t exist, then we can use the shortid npm package to generates a unique key.

var shortid = require('shortid');
function createNewTodo(text) {
return {
completed: false,
id: shortid.generate(),
text
}
}

However it is an important point to note here is there are many cases in which we can safely use an index as the key.

  • the list and items are static — they are not computed and do not change
  • the items in the list have no ids
  • the list is never reordered or filtered

When all of these conditions are met, we may safely use the index as a key.

Spreading props on DOM elements

We generally spread the properties to the elements to avoid writing every single one manually.

However, when we spread props into a DOM element, we run the risk of adding unknown HTML attributes which are NOT required and is a bad practice.

Let's take an example

const Spread = () => <div hero="superman" />

The message we get looks like the following, since the hero property is not valid for a div element.

Unknown props 'hero' on <div> tag. Remove this prop from the element

In the above case, it was easy to figure out what we are passing incorrectly and remove it. However, in the case of a spread operator, we can’t control what all properties will get passed from the parent like in the below case.

const Spread = props => <div {...props} />

Therefore instead of spreading props, it is recommended to set specific attributes.

const SpecificAttribute = props => 
<div specificAttr={props.specificAttr} />

Update Components Only When Necessary and Required

Whenever any component’s props or state changes, React checks whether it needs to update the actual DOM or not.

It does this by comparing the existing rendered component with the newly returned component. If they are the same, React does nothing, else it will update the DOM based on the new component.

React only updates the changed DOM nodes, it will not re-render the whole page. However, it may be the case that single rendering is taking time, and we don’t want to update the nodes in all the cases.

To handle this, what we can do is override the life-cycle function shouldComponentUpdate which automatically gets triggered before the re-rendering process starts. We can override its default implementation to return false based on our scenario.

We can also use React.PureComponent rather than updating shouldComponentUpdate(). However, I will leave this to developers which one they want to use.

Immutable Data Structures

We need to use immutable data structures if we want to use React.PureComponent to automatically check for complex state changes. It is not an architecture or design pattern, it is more like a way of writing code.

Setting up immutable data structures involves creating copies of objects that need to get updated rather than updating the same object itself.

In this way, we can simplify the process of object reconciliation to detect the changes. However, we should keep in mind that, it also has restrictions, we cant change immutable data once it's created.

Benefits:

  • No side-effects
  • Immutable data objects are simpler to create, test, and use
  • Helps prevent temporal coupling, it is a type of coupling where code is dependent on time in some way
  • Helps us to write logic that can be used to quickly check if there is some updates in state without checking the data recursively

We can use the below libraries that provide a set of immutable data structures.

  • Immutability Helper: This is a good library when it comes to mutating a data copy without changing the source.
  • Immutable.js: This is my favorite library as it provides a lot of persistent immutable data structures, including: List, Stack, Map, OrderedMap, Set, OrderedSet, and Record.
  • Seamless-immutable: A library for immutable JavaScript data structures that are backward-compatible with normal arrays and objects.
  • React-copy-write: An immutable React state management library with a simple mutable API, memoized selectors, and structural sharing.

Summary

The main key to fine-tuning any React app lies in making sure that components only update when they absolutely need to.

Also, It should go without saying, we need to make sure that performance optimization should be a regular priority rather than leaving it to the end.

Lastly, if we are making any performance-related changes, we need to run benchmarks analysis before and after changes to see if there are any improvements.

There are still many ways or areas that we can cover to optimize the performance. However, for the sake of brevity, I have not included all those in a single article. I will try to include all those in future article.

That’s it for now. Happy Coding!