React.PureComponent Considered Harmful

Frankie Bagnardi
HackerNoon.com
2 min readMar 6, 2017

--

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!

--

--