paint-brush
React.PureComponent Considered Harmfulby@f.bagnardi
10,747 reads
10,747 reads

React.PureComponent Considered Harmful

by Frankie BagnardiMarch 6th, 2017
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

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.

Company Mentioned

Mention Thumbnail
featured image - React.PureComponent Considered Harmful
Frankie Bagnardi HackerNoon profile picture

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!