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 F.

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 react-addons-perf library you can get an overview of your app’s overall performance.

The usage is very simple:

Import Perf from 'react-addons-perf'
Perf.start();
// use the app
Perf.stop();
Perf.printWasted();

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 printInclusive() or the printExclusive() functions), or even print the DOM manipulation operations (using the printOperations() function).

Taking Benchmarking A Step Further

If you are a visual person, then react-perf-tool is just the thing you need.

react-perf-tool is based on the react-addons-perf 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 shouldComponentUpdate method comes into play.

function shouldComponentUpdate(nextProps, nextState) {
    return true;
}

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 false 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:

function shouldComponentUpdate(nextProps, nextState) {
    return nextProps.id !== this.props.id;
}

Using a React.PureComponent

To ease and automate a bit this optimization technique, React provides what is known as “pure” component. A React.PureComponent is exactly like a React.Component that implements a shouldComponentUpdate() function with a shallow prop and state comparison.

A React.PureComponent is more or less equivalent to this:

class MyComponent extends React.Component {
    shouldComponentUpdate(nextProps, nextState) {
        return shallowCompare(this.props, nextProps) && shallowCompare(this.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 forceUpdate() to update your component.

Making Data Immutable

What if you could use a React.PureComponent 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 Object.assign or _.extend (from Underscore.js or Lodash):

const newValue2 = Object.assign({}, oldValue);
const newValue2 = _.extend({}, oldValue);

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

var map1 = Immutable.Map({a:1, b:2, c:3});
var map2 = map1.set('b', 2);
assert(map1.equals(map2) === true);
var map3 = map1.set('b', 50);
assert(map1.equals(map3) === false);

Here, Immutable.Map is provided by the library Immutable.js.

Every time a map is updated with its method set, 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 create-react-app, 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()
<TopBar onUpload={this.handleUpload.bind(this)} />
// ...as do inlined arrow functions
<TopBar onUpload={files => this.handleUpload(files)} />

This will cause the render() 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) {
        super(props);
        this.handleUpload = this.handleUpload.bind(this);
    }
    render() {
        …
        <TopBar onUpload={this.handleUpload} />
        …
    }
}

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.

With eslint-plugin-react, 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.

Understanding the Basics

What React component should you optimize first?

You should always begin my measuring the performance of your code. Sometimes seemingly “simple” code can be the cause of your app slowing down. Measure the performance of your React code with the tools it has to offer before diving into optimizing it.

About the author

William Wang, China
member since June 26, 2016
William is a full-stack developer who has worked as a freelancer and as a senior developer/CTO for local IT companies. He's developed and completed many web and mobile projects. He mainly uses PHP/MySQL for the back-end and jQuery or React.js for the front-end. William is a passionate learner who picks up things quickly, loves coding, and truly enjoys the perks of freelancing.. [click to continue...]
Hiring? Meet the Top 10 Freelance React.js Developers for Hire in June 2017

Comments

Lê Anh Quân
Thanks William for the great post, very deep and well written article. I have a question, it is a bit off topic but would be great if you could help answer: Redux is nowadays the dominant framework for React app, but as I understand, its single store architecture will force the whole app to re-render on every user action, is it right? If yes, it is a really horrible performance issue, right? Thanks again for the great post
Juraj
Thanks for interesting post. Just small note - you probably wanted to compare states instead of comparing props twice - in code sample `return shallowCompare(this.props, nextProps) && shallowCompare(this.props, nextProps);` in section: Using a React.PureComponent
elQueFaltaba
Interesting one. One more thing to add would be to use functional components if possible, that is, if you don't depend on the react component lifecycle. A simple function with a return according to props is always going to be faster than rendering a React element.
elQueFaltaba
It doesn't need to. When you connect your components to Redux (mapStateToProps), you tell the component what part of the store is interesting to the particular view (container), so it only triggers any re-render if that particular part changes .. Then, using these techniques, you implement the logic of which components should really be re-rendered according to these changes. You could also have pre-computed values from the Redux store to simplify this even more, and by this, do less re-renders ..
Lê Anh Quân
Awesome, thanks a lot for your answer, it really makes sense
Ivan Rogić
Thank you for the great article! Anyone interested in a similar writing about the same topic feel free to check: https://www.toptal.com/react/react-redux-and-immutablejs
Ivan Rogić
Feel free to check my post a year back about the performance improvements with React, Redux and immutableJS: https://www.toptal.com/react/react-redux-and-immutablejs
William Wang
Actually, stateless (functional) components are not any faster than the stateful (class), because stateless component is wrapped in a class internally. check here: https://twitter.com/dan_abramov/status/755343749983657986
William Wang
Yes, thank you for point this out. it should be: `return shallowCompare(this.props, nextProps) && shallowCompare(this.state, nextState);`
Tmoney
However, this will change in the new version of React, or so I have been told. In the future, stateless functional components will be lighter weight and faster.
Alexander Zinchuk
As for binding event handlers in JSX — there is a method decorator for that https://www.npmjs.com/package/autobind-decorator .
disqus_EV1IX1cmTZ
That's right @disqus_f1m3rPAaBA:disqus
Marcelo Carneiro
Very nice article and great tips, thanks for sharing.
comments powered by Disqus
Subscribe
The #1 Blog for Engineers
Get the latest content first.
No spam. Just great engineering posts.
The #1 Blog for Engineers
Get the latest content first.
Thank you for subscribing!
You can edit your subscription preferences here.
Trending articles
Relevant Technologies
About the author
William Wang
JavaScript Developer
William is a full-stack developer who has worked as a freelancer and as a senior developer/CTO for local IT companies. He's developed and completed many web and mobile projects. He mainly uses PHP/MySQL for the back-end and jQuery or React.js for the front-end. William is a passionate learner who picks up things quickly, loves coding, and truly enjoys the perks of freelancing..