React is usually pretty fast, but it’s easy to make small mistakes that lead to performance issues. Slow component mounts, deep component trees, and unnecessary render cycles can quickly add up to an app that feels slow.
Luckily there are lots of tools, some even built in to React, that help with diagnosing performance issues. In this series we’ll highlight tools and techniques for making React apps fast. Each post will also have an interactive, and (hopefully) fun demo!
One of the most common issues that affects performance in React is unnecessary render cycles. By default, React components will re-render whenever their parent renders, even if their props didn’t change.
For example, if I have a simple component like this:
class DumbComponent extends Component {render() {return <div> {this.props.value} </div>;}}
With a parent component like this:
class Parent extends Component {render() {return <div><DumbComponent value={3} /></div>;}}
Whenever the parent component renders, DumbComponent
will re-render, despite its props not changing.
Generally, if render
runs, and there were no changes to the virtual DOM, it is a wasted render cycle since the render
method should be pure and not have any side effects. In a large-scale React app, it can be tricky to detect places where this happens, but luckily, there’s a tool that can help!
why-did-you-update
is a library that hooks into React and detects potentially unnecessary component renders. It detects when a component’s render
method is called despite its props not having changed.
npm i --save-dev why-did-you-update
import React from 'react'
if (process.env.NODE_ENV !== 'production') {const {whyDidYouUpdate} = require('why-did-you-update')whyDidYouUpdate(React)}
Note that this tool is great in local development but make sure it’s disabled in production since it will slow down your app.
why-did-you-update
monitors your app as it runs and logs components that may have changed unnecessarily. It lets you see the props before and after a render cycle it determined may have been unnecessary.
Once you’ve identified components in your app that are re-rendering unnecessarily, there are a few easy fixes.
In the above example, DumbComponent
is a pure function of its props. That is, the component only needs to re-render when its props change. React has a special type of component built-in called PureComponent
that is meant for exactly this use case.
Instead of inheriting from React.Component, use React.PureComponent like this:
class DumbComponent extends PureComponent {render() {return <div> {this.props.value} </div>;}}
Then, the component will only re-render when its props actually change. That’s it!
Note that PureComponent
does a shallow comparison of props, so if you use complex data structures, it may miss some prop changes and not update your components.
shouldComponentUpdate
is a component method called before render
when either props
or state
has changed. If shouldComponentUpdate
returns true, render
will be called, if it returns false, nothing happens.
By implementing this method, you can instruct React to avoid re-rendering a given component if its props don’t change.
For example, we could implement shouldComponentUpdate
in our dumb component from above like this:
class DumbComponent extends Component {shouldComponentUpdate(nextProps) {if (this.props.value !== nextProps.value) {return true;} else {return false;}}
render() {return <div>foo</div>;}}
To demonstrate why-did-you-update
, I installed the library in the TodoMVC app on Code Sandbox, an online React playground. Open the browser console and add some TODOs to see the output.
Notice that a few components in the app are rendering unnecessarily. Try implementing the techniques described above to prevent unnecessary renders. If done correctly, there should be no output from why-did-you-update
in the console.
why-did-you-update
only works in local development. If you’re interested in understanding performance issues in your production app, try LogRocket.
LogRocket is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong.
LogRocket instruments your app to record performance timings, Redux actions/state, logs, errors, network requests/responses with headers + bodies, and browser metadata. It also records the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.
LogRocket | Logging and Session Replay for JavaScript Apps_LogRocket helps you understand problems affecting your users, so that you can get back to building great software._logrocket.com
why-did-you-update
is a handy tool for detecting potentially unnecessary component re-renders, helping you make your app perform better.
Since why-did-you-update
only works in development, check out LogRocket, for diagnosing bugs and performance issues in production.
For more React performance tips, check out parts 1 and 3 of this series:
Make React Fast Again [Part 1]: Performance Timeline_React is usually pretty fast, but it’s easy to make small mistakes that lead to performance issues. Slow component…_blog.logrocket.com
Make React Fast Again [Part 3]: Highlighting Component Updates_React is usually pretty fast, but it’s easy to make small mistakes that lead to performance issues. Slow component…_blog.logrocket.com
It’s tough to keep up-to-date on front-end dev. Join our weekly mailing list to learn about new tools, libraries and best practices that will help you build better apps: