React.PureComponent Considered Harmful

Written by f.bagnardi | Published 2017/03/06
Tech Story Tags: react | javascript | performance

TLDRvia the TL;DR App

EDIT: I no longer stand by the sentiment of this post, but the technical concerns that cause PureComponent to frequently fail to prevent renders are still worth understanding.

Wasted renders are a big problem in performant React.js code. The React core team came up with a solution: React.PureComponent. Let’s look at how it works, what problems it solves, and what problems it doesn’t solve.

So, what is it? PureComponent is exactly like React.Component with one difference: it implements shouldComponentUpdate. This allows it to prevent renders based on some heuristic. PureComponent implements this as a shallow equality check on the new props vs the old props, and likewise for state. So if you have the props ‘a’ and ‘b’, it essentially does the following:

This is great in theory because we can prevent expensive renders, drastically improving our performance. But, wait! “This is too good to be true”, I hear you saying. Well… you’re right. We run into issues from these !== checks. Let’s say Foo is a component extending from React.PureComponent. Here are some example uses of Foo:

These three examples share the same problem: Foo will always rerender because the shouldComponentUpdate always returns true! In the first two, the shouldComponentUpdate checks if this.props.x !== nextProps.x, and since {} !== {}, and likewise for the .map, it will always see the props as having changed. The same thing happens with the children prop, where this.props.children !== nextProps.children.

The minor issue here is that we’re doing the shouldComponentUpdate check with no gain, which is more expensive than the example I gave above because it has to iterate over the keys of both the current and next props objects.

The larger issue is that we assume we’ve solved a performance problem, while only making it slightly worse most of the time.

Hmm… so how do we prevent needless renders and diffing? A trick! Enter: react-update-if-changed.

In this example, Foo is using react-update-if-changed instead of PureComponent. Instead of it checking if this.props.children !== nextProps.children, it just checks the updateIfChanged prop for equality. One equality check; that’s it.

There are two remaining problems.

  1. We might have multiple values that can change, or one value that should be compared by deep equality. You can use the updateIfChangedEqual={[a, b]} prop in this situation.
  2. We still have to compute the <h1> in the above example (but not diff it), which might actually be expensive to compute. See the UpdateIfChanged component in react-update-if-changed which addresses this.

React.PureComponent is rarely useful, but don’t give up hope on great performance in React.js!

Hacker Noon is how hackers start their afternoons. We’re a part of the @AMIfamily. We are now accepting submissions and happy to discuss advertising & sponsorship opportunities.

To learn more, read our about page, like/message us on Facebook, or simply, tweet/DM @HackerNoon.

If you enjoyed this story, we recommend reading our latest tech stories and trending tech stories. Until next time, don’t take the realities of the world for granted!


Published by HackerNoon on 2017/03/06