Building High Performance React Applications

Okay, we all know that React was built with performance in mind, but when is React slow? I want to break down for you, dear reader, common bottlenecks in React and when you might be making your program work harder than it should.

First of all, we need to set a baseline. How the heck do we measure performance in a React Application? Well, I am glad you asked! As of React 16, React has a performance monitoring tool baked into the vanilla development mode of React!

Okay, let’s check it out. When you are in a development build, you can now perform a performance audit and see how your React components are spending their time. This feature can be used to fine tune your app and find expensive components and methods. This is also the tool we will be using to measure the performance of our app.

I’m not going to go into great detail of how this tools works, but if you want a more detailed walk through, check out this article by Ben Schwarz.

For example, let’s try it out. I have built the least performant React application possible, you can check out the code here on my GitHub.

Let’s go through and see how these tips boost the performance of our crummy ‘lil app.

Initial performance audit of our slow React app

As we update items on this list, we can see through the performance audit that every time I add a new item to the list through the form, every single item in the list has to re-render to the DOM. This process takes approximately 34 ms for every single re-render.

Now that we know how to measure performance on a React application and we have a performance baseline, let’s get to the thing that you came to this blog post to learn about. How exactly do you make a high performance React app? Well, the short answer is only render to the DOM when you really need to. The long answer is a little more involved… ;)

Using our example app, and our initial analysis, we see that there is a LOT of re-rendering happening when new items are added. We want to tell React to only re-render the parts of the app that we care about. Let’s dig into specific ways to accomplish this.


Use 🔑Key🔑 Correctly

So, who has this had this happen to them before? You are writing a react app and you start looping over a list of data and you are dynamically creating React nodes. All is fine and your app is rendering to the DOM just fine, but you see this little warning pop up for you in the console.

Console warning you should see if you do not supply a key

I don’t know about you, but the first thing I did was put in Math.Random() in the key field, and BOOM, the warning magically disappeared! Problem solved! Well, not so fast, it turns out that even though React is no longer complaining, you are actually messing with how React keeps track of those nodes in the virtual DOM.

Sonic says “Do not abuse the key!”

The key attribute is actually used by React to keep track of and identify unique nodes. This element allows React to easily keep track of how your application is changes and helps it decide if it needs to re-render to the DOM or not. And by using Math.Random() or the index in an array to track the unique key, every single time the list re-renders or the data changes, React loses track of your element and has to start over from scratch. You can learn more about how the key is used here. Do not forget to supply an appropriate key!

So how does using the key attribute correctly affect our performance? Let’s check it out!

We went from 34 ms to 16 ms. We just cut the render time in half by using key’s correctly!


Manage shouldComponentUpdate()

shouldComponentUpdate()is a React life cycle method used to improve performance of React applications by defining exactly when you want your component to re-render. By default, React will re-render your component each and every time the state or props change. However, there might be instances when you do not want your component even if your state has changed.

In this example, we are passing in the nextProps and nextState and we are returning a boolean that reports the state/prop changes that we actually care about and that we actually want to re-render on. React is able to ignore all other changes. Here’s the code of how the use shouldComponentUpdate().

class Item extends Component {
  shouldComponentUpdate(nextProps, nextState) {
if (this.props.title !== nextProps.title) {
return true;
}
return false;
}
  render() {
return <h3>{ this.props.title }</h3>
}
};

When we take control and tell React about the state changes that we care about, how does that affect our re-render time?

Performance audit after implementing shouldComponentUpdate()

We’ve cut the re-render time from approximately 16 ms to 9 ms. We’ve nearly cut the render time in half again!

GOTTA GO FAST!

Extend ✨ PureComponent ✨

shouldComponentUpdate() is wonderful and it does great things for helping improve the performance of our React applications, but you should consider using the built-in PureComponent instead of writing shouldComponentUpdate() by hand. A PureComponent performs a shallow comparison of props and state, and reduces the chance that you’ll skip a necessary update.

When React is performing a shallow comparison, it treats scalar values differently from objects. When it is comparing scalar values (numbers, strings) it compares their values. When comparing objects, it does not compare their’s attributes — only their references are compared (e.g. “do they point to same object?). This gif shows how JavaScript performs a deep or shallow comparison

Shallow compare is efficient way to detect changes. It should be noted that shallow comparisons, expect that you don’t mutate data (which we will address when we talk about in the immutable data section below).

So, what does a PureComponent look like in code? For those who want a real code snippet, here it is:

class Item extends PureComponent {
render() {
return <h3>{ this.props.title }</h3>
}
};

For those who want to see the dramatic reduction and increased clarity PureComponents brings over using shouldComponentUpdate(), check out this incredible gif I made!

Look at the dramatic reduction and increased clarity PureComponents brings over using shouldComponentUpdate()

Isn’t it so much shorter and easier to read than before? This gif perfectly sums up how I feel after I refactor a code base to use PureComponents.

Doesn’t it feel good to not have to write all that code?

Okay, so it looks pretty, but do PureComponents actually make our application perform faster? If it is truly a replacement for shouldComponentUpdate(), than we should expect that the performance boost should be equivalent.

PureComponents give you the same performance boost as shouldComponentUpdate()

We can see that we see exactly the same performance gains as when we use shouldComponentUpdate(). Yahoo!


Use 🔒Immutable🔒 Data

Immutable is one of those fancy programming words you’ve probably heard tossed around, but you might not know what it means. Immutable is a fancy word that means instead of changing data you are instead making new copies of objects/arrays. Using immutable data in your React app allows the React diffing algorithm to make tracking the changes to your app cheap. Below is an example of how differences are tracked with Mutable and Immitable data. In the first mutable example, JavaScript needs to check each key in the object to check for differences, but in the Immutable example, JavaScript is able to check if the object pointer is in a different memory location. This is SO MUCH FASTER!

For more information on how immutable data helps improve the performance of your React application, check out this info straight from the source.


Use Stateless Components

Okay, to be honest, I’m not exactly sure why using stateless components is faster than using React components with state, but Dan Abramov reports that in version 16+ of React, stateless components give a small performance boost. I haven’t actually seen any information or explanation about why is this, but if Dan says it’s true, so I believe it. If anyone has any info on why this is, please let me know in the comments below.

Tweet from Dan explaining that Stateless Components are faster in React 16+

Go Universal

Universal (or Isomorphic) React won’t make your whole application faster, but it will make your component initial render to go much faster. And sometimes, performance is all about making your user think your fast ;)

Universal rendering works by performing the initial render of your React component on the server. The server than sends an pre-rendered HTML string of your initial render, CSS, and JS. This can be easily cached on your servers to further reduce and reuse your initial render. Using Universal React allows the users of your application to see and interact with your site while React is still firing up behind the scenes.

Flow of how Isomorphic React component render on the client

Universal React works great if you have a humongous app that takes a long time to do the initial render. You can find out more information about isomorphic React here:


⚡️ Build React for Production ⚡️

When you are building your React component on your development machine, it is expected that you build it using development mode. This is because this mode includes a bunch of helpful tools to help you debug you application. Development mode includes the performance audit tool that have been using to benchmark our app. However, when you run your app in production mode, React automatically strips out all of the development tools and builds a minified version that runs faster in the browser. In fact, the production build can even make your app run two to eight times faster! Let’s check it out.

Running our app in “Production” mode

When running the production build, the performance auditing tool has been removed. Since this is missing, we will now look at how quickly the component can repaint the DOM after an update using the default performance tools in Chrome. With the production build of our app, we can see that we now re-paint in 6 ms. Woohoo!

More information about building your React app in production mode can be found here.


Analyze Your Webpack Bundle 🔬

This tip isn’t exactly React specific, but most of us use Webpack as their bundler with React, and I have found that this is actually one of the most beneficial things we have implemented to make our React apps faster.

We have started to to add a Webpack analysis into our development workflow. Using Webpack Bundle Analyzer, we check to make sure that nothing unexpected has made it’s way into our final bundle. We also use this step to ensure that there are no unexpectedly large packages has slipped in.

Analyzing your bundle and reducing bundle size is important to improve application performance because the more data you are sending across the internet tubes, the slower it takes get to the end user and the longer it takes to parse and load the bundle.

Our team has included Webpack Bundle Analyzer in our build process to help keep the package size under control. It’s easy for us to pull in a new npm package in order to provide a quick fix for our app, but often times, it’s not clear how that actually impacts our final bundle size.

Webpack Bundle Analyzer makes it easy to visually see what your bundle is made of

Make It Work, Then Make It Fast 🏃💨

I personally believe that this is the most important point of all. When building any application, you should focus on getting your app working first, and only focus on making it fast once you have it released and you see that you have performance issues (note: this is generally true, however, I am aware that there are situations where you need to focus on speed from the very beginning).

Often times, I see engineers to focused on making a “perfect” app that they fail to ever finish it and release it. Releasing an app (even if it’s not perfect) is even more important when working on a professional software project.


Alright, let’s recap everything learned. If you want to make your React applications fast you should do the following:

  • Use 🔑key🔑 correctly
  • Manage shouldComponentUpdate()
  • Extend ✨ PureComponent ✨
  • Use 🔒immutable🔒 data
  • Use stateless components
  • Go universal
  • ⚡️ Build React for production ⚡️
  • Analyze your Webpack bundle 🔬
  • Make it work, then make it fast 🏃💨

There you have it, I hope these are some practical and easy to implement things you can do to start making your React apps faster. If I missed anything, please feel free to let me know in the comments below.

Thanks for reading!


My name is Joe Karlsson, and I am a Software Engineer from the frozen tundra known as Minneapolis, Minnesota. I write code, build teams and give talks. You can follow me on: