Efficient React Components: A Guide to Optimizing React Performance

Since its introduction, React has changed the way front-end developers think of building web apps. With virtual DOM, React makes UI updates as efficient as they can ever be, making your web app snappier. But, why do moderately sized React web apps still tend to perform poorly?

Well, the clue is in how you are using React.

A modern front-end library like React doesn’t magically make your app faster. It requires the developer to understand how React works and how the components live through the various phases of the component lifecycle.

With React, you can gain a lot of the performance improvements that it has to offer by measuring and optimizing how and when your components render. And, React provides just the tools and functionalities necessary to make this easy.

Speed up your React app by optimizing your components’ render-diff process.

In this React tutorial, you will learn how you can measure the performance of your React components and optimize them to build a much more performant React web app. You will also learn how a few JavaScript best practices also help in making your React web app deliver a much more fluent user experience.

How Does React Work?

Before we dive into the optimization techniques, we need to have a better understanding of how React works.

At the core of React, you have the simple and obvious JSX syntax, and React’s ability to build and compare virtual DOMs. Since its release, React has influenced many other front-end libraries. Libraries such as Vue.js also rely on the idea of virtual DOMs.

Here is how React works:

Each React application begins with a root component, and is composed of many components in a tree formation. Components in React are “functions” that render the UI based on the data (props and state) it receives.

We can symbolize this as



UI = F(data)

Users interact with the UI and cause the data to change. Whether the interaction involves clicking a button, tapping on an image, dragging list items around, AJAX requests invoking APIs, etc., all those interactions only change the data. They never cause the UI to change directly.

Here, data is everything that defines the state of the web application, and not just what you have stored in your database. Even bits of front-end states (e.g., which tab is currently selected or whether a checkbox is currently checked) are part of this data.

Whenever there is a change in this data, React uses the component functions to re-render the UI, but only virtually:

UI1 = F(data1)
UI2 = F(data2)

React computes the differences between the current UI and the new UI by applying a comparison algorithm on the two versions of its virtual DOM.

Changes = Diff(UI1, UI2)

React then proceeds to apply only the UI changes to the real UI on the browser.

When the data associated with a component change, React determines if an actual DOM update is required. This allows React to avoid potentially expensive DOM manipulation operations in the browser, such as creating DOM nodes and accessing existing ones beyond necessity.

This repeated diffing and rendering of components can be one of the primary sources of React performance issues in any React app. Building a React app where the diffing algorithm fails to reconcile effectively, causing the entire app to be rendered repeatedly can result in a frustratingly slow experience.

Where to Start Optimizing?

But what exactly is it that we optimize?

You see, during the initial render process, React builds a DOM tree like this:

A virtual DOM of React components

Given a part of the data changes, what we want React to do is re-render only the components that are directly affected by the change (and possibly skip even the diff process for the rest of the components):

React rendering an optimal number of components

However, what React ends up doing is:

React wasting resources rendering all components

In the image above, all of the yellow nodes are rendered and diffed, resulting in wasted time/computation resources. This is where we will primarily put our optimization efforts in. Configuring each component to only render-diff when it is necessary will allow us to reclaim these wasted CPU cycles.

Developers of the React library took this into consideration and provided a hook for us to do just that: a function that lets us tell React when it is okay to skip rendering a component.

Measuring First

As Rob Pike puts it rather elegantly as one of his rules of programming:

Measure. Don’t tune for speed until you’ve measured, and even then don’t unless one part of the code overwhelms the rest.

Do not start optimizing code that you feel may be slowing your app down. Instead, let React performance measuring tools guide you through the way.

React has a powerful tool just for this. Using the


library you can get an overview of your app’s overall performance.

The usage is very simple:

Import Perf from <span class="hljs-string">'react-addons-perf'</span>
<span class="hljs-comment">// use the app</span>

This will print a table with the amount of time components wasted in rendering.

Table of components wasting time in rendering

The library provides other functions that let you print different aspects of the wasted time separately (e.g., using the


or the


functions), or even print the DOM manipulation operations (using the



Taking Benchmarking A Step Further

If you are a visual person, then


is just the thing you need.


is based on the


library. It gives you a more visual way of debugging performance of your React app. It uses the underlying library to get measurements and then visualizes them as graphs.

A visualization of components wasting time in rendering

More often than not, this is a much more convenient way of spotting bottlenecks. You can use it easily by adding it as a component to your application.

Should React Update The Component?

By default, React will run, render the virtual DOM, and compare the difference for every component in the tree for any change in its props or state. But that is obviously not reasonable.

As your app grows, attempting to re-render and compare the entire virtual DOM at every action will eventually slow down.

React provides a simple way for the developer to indicate if a component needs re-rendering. This is where the


method comes into play.

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">shouldComponentUpdate</span><span class="hljs-params">(nextProps, nextState)</span> {</span>
    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;

When this function returns true for any component, it allows the render-diff process to be triggered.

This gives the you a simple way of controlling the render-diff process. Whenever you need to prevent a component from being re-rendered at all, simply return


from the function. Inside the function, you can compare the current and next set of props and state to determine whether a re-render is necessary:

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">shouldComponentUpdate</span><span class="hljs-params">(nextProps, nextState)</span> {</span>
    <span class="hljs-keyword">return</span> nextProps.id !== <span class="hljs-keyword">this</span>.props.id;

Using a React.PureComponent

To ease and automate a bit this optimization technique, React provides what is known as “pure” component. A


is exactly like a


that implements a


function with a shallow prop and state comparison.



is more or less equivalent to this:

<span class="hljs-keyword">class</span> MyComponent extends React.Component {
    shouldComponentUpdate(nextProps, nextState) {
        <span class="hljs-keyword">return</span> shallowCompare(<span class="hljs-keyword">this</span>.props, nextProps) &amp;&amp; shallowCompare(<span class="hljs-keyword">this</span>.state, nextState);

As it only performs a shallow comparison, you may find it useful only when:

  • Your props or states contain primitive data.
  • Your props and states have complex data, but you know when to call

    to update your component.

Making Data Immutable

What if you could use a


but still have an efficient way of telling when any complex props or states have changed automatically? This is where immutable data structures make life easier.

The idea behind using immutable data structures is simple. Whenever an object containing complex data changes, instead of making the changes in that object, create a copy of that object with the changes. This makes detecting changes in data as simple as comparing the reference of the two objects.

You can use




(from Underscore.js or Lodash):

<span class="hljs-keyword">const</span> newValue2 = <span class="hljs-built_in">Object</span>.assign({}, oldValue);
<span class="hljs-keyword">const</span> newValue2 = _.extend({}, oldValue);

Even better, you can use a library that provides immutable data structures:

<span class="hljs-keyword">var</span> map1 = Immutable.Map({a:<span class="hljs-number">1</span>, b:<span class="hljs-number">2</span>, c:<span class="hljs-number">3</span>});
<span class="hljs-keyword">var</span> map2 = map1.set(<span class="hljs-string">'b'</span>, <span class="hljs-number">2</span>);
assert(map1.equals(map2) === <span class="hljs-literal">true</span>);
<span class="hljs-keyword">var</span> map3 = map1.set(<span class="hljs-string">'b'</span>, <span class="hljs-number">50</span>);
assert(map1.equals(map3) === <span class="hljs-literal">false</span>);



is provided by the library Immutable.js.

Every time a map is updated with its method


, a new map is returned only if the set operation changed the underlying value. Otherwise, the same map is returned.

You can learn more about using immutable data structures here.

More React App Optimization Techniques

Using the Production Build

When developing a React app, you are presented with really useful warnings and error messages. These make identifying bugs and issues during development a bliss. But they come at a cost of performance.

If you look into React’s source code, you will see a lot of

if (process.env.NODE_ENV != 'production')

checks. These chunks of code that React is running in your development environment isn’t something needed by the end user. For production environments, all of this unnecessary code can be discarded.

If you bootstrapped your project using


, then you can simply run

npm run build

to produce the production build without this extra code. If you are using Webpack directly, you can run

webpack -p

(which is equivalent of

webpack --optimize-minimize --define process.env.NODE_ENV="'production'"


Binding Functions Early

It is very common to see functions bound to the context of the component inside the render function. This is often the case when we use these functions to handle events of child components.

// Creates a new `handleUpload` function during each render()
&lt;TopBar onUpload={this.handleUpload.bind(this)} /&gt;
// ...as do inlined arrow functions
&lt;TopBar onUpload={files =&gt; this.handleUpload(files)} /&gt;

This will cause the


function to create a new function on every render. A much better way of doing the same is:

class App extends React.Component {
    constructor(props) {
        this.handleUpload = this.handleUpload.bind(this);
    render() {
        &lt;TopBar onUpload={this.handleUpload} /&gt;

Using Multiple Chunk Files

For singl-page React web apps, we often end up bundling all of our front-end JavaScript code in a single minified file. This works fine for small to moderately sized web apps. But as the app starts to grow, delivering this bundled JavaScript file to the browser in itself can become a time consuming process.

If you are using Webpack to build your React app, you can leverage its code splitting capabilities to separate your built app code into multiple “chunks” and deliver them to the browser on an as-needed basis.

There are two type of splitting: resource splitting and on-demand code splitting.

With resource splitting, you split resource content into multiple files. For example, using CommonsChunkPlugin, you 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.

A more notable feature of Webpack is on-demand code splitting. You can use it to split code into a chunk 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.

You can learn more about Webpack code splitting here.

Enabling Gzip on Your Web Server

React app’s bundle JS files are commonly very big, so to make the web page load faster, we can enable Gzip on the web server (Apache, Nginx, etc.)

Modern browsers all support and automatically negotiate Gzip compression for HTTP requests. Enabling Gzip compression can reduce the size of the transferred response by up to 90%, which can significantly reduce the amount of time to download the resource, reduce data usage for the client, and improve the time to first render of your pages.

Check the documentation for your web server on how to enable compression:

Using Eslint-plugin-react

You should use ESLint for almost any JavaScript project. React is no different.



, you will be forcing yourself to adapt to a lot of rules in React programming that can benefit your code on the long run and avoid many common problems and issues that occur due to poorly written code.

Make Your React Web Apps Fast Again

To make the most of React, you need to leverage its tools and techniques. A React web app’s performance lies in the simplicity of its components. Overwhelming the render-diff algorithm can make your app perform poorly in frustrating ways.

Before you can optimize your app, you will need understand how React components work and how they are rendered in the browser. The React lifecycle methods give you ways to prevent your component from re-rendering unnecessarily. Eliminate those bottlenecks and you will have the app performance your users deserve.

Although there are more ways of optimizing a React web app, fine tuning the components to update only when required yields the best performance improvement.

How do you measure and optimize your React web app performance? Share it in the comments below.

This article is originally posted in Toptal.

Leave a Reply

Your email address will not be published. Required fields are marked *