Ben Edelstein Founder @LogRocket, formerly @Google

Make React Fast Again [Part 2]: why-did-you-update

2 min read 803

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!


The Problem: Unnecessary Render Cycles

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  {this.props.value} ;
  }
}

With a parent component like this:

class Parent extends Component {
  render() {
    return 
      
    ;
  }
}

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?

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.

Setup

  1. Install with npm: npm i --save-dev why-did-you-update
  2. Add this snippet anywhere in your app:
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.

Understanding the output

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.

Fixing unnecessary renders

Once you’ve identified components in your app that are re-rendering unnecessarily, there are a few easy fixes.

Use PureComponent

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  {this.props.value} ;
  }
}

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.

Implement shouldComponentUpdate

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 foo;
  }
}

Demo!

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.

https://codesandbox.io/s/xGJP4QExn

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.

Debugging Performance Issues in Production

why-did-you-update only works in local development. If you’re interested in understanding performance issues in your production app, try LogRocket.

https://logrocket.com/signup/

LogRocket is like a DVR for web apps, recording literally everything that happens on your site. Instead of guessing why problems happen, you can replay sessions with bugs or performance issues to quickly understand the root cause.

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.

Session Replay | Product Analytics | Error Tracking

LogRocket helps you understand problems affecting your users, so that you can get back to building great software.

Conclusion

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

Make React Fast Again [Part 3]: Highlighting Component Updates

Ben Edelstein Founder @LogRocket, formerly @Google

Leave a Reply