> So all you have to do is use PureComponent everywhere and you’re good to go. There’s nothing more to it. Enjoy your new blazing fast React app!
(I work on React.) This isn't quite right. If we recommended that PureComponent be used everywhere, it would probably be the default already. Rather -- the comparison to decide whether or not a component should be rerendered costs something, and in the case that you do want to rerender, all of the time spent checking whether you should have rerendered is wasted.
Instead, we'd suggest you be conscious of where you need to do the comparisons. It's usually only in a couple of places in your app. Good candidates are on the children of a long list or around large parts of the app that change independently (that is, cases where you know the parent should often rerender but the child shouldn't). A few well-placed shouldComponentUpdate (or PureComponent) uses can go a long way.
Hi Ben! At the React conference, I asked Sebastian Markbåge (also a React author) why `PureComponent` wasn't the default and he said there were already too many new concepts when React was released, and it would have made adoption harder. But he implied that maybe it should be the default. (Then again, alcohol was involved so I could be misremembering.)
When using immutable data structures the comparison in `shouldComponentUpdate` is very cheap. Assuming that, using pure components everywhere is very tempting for simplicity.
Correct me if I'm wrong, but React creates an object for every component to pass props around. Constructing that object is linear in the number of props. An additional `shouldComponentUpdate` check for each component is also linear in the number of props. So using pure components everywhere is at worst adjusting the constant.
Also, in a world where PureComponent is the default, perhaps React could monitor the "hit rate" of `shouldComponentUpdate` and decide to not call it if a component returns true too often?
First off, thanks for your work on React! Makes all of our lives easier as developers :)
As dmnd pointed out, I'm not entirely convinced that dropping PureComponent everywhere is not a good idea.
For our app specifically, we unfortunately do data loading in a lot of places, which means that there are quite a bit more than just few places that can benefit from being a PureComponent. Our current idea is to try to make everything a PureComponent, and go back and 'unpurify' the places that have wasteful sCU comparisons. This might not turn out to be a good idea though, for the reasons you mentioned.
I'll make sure to do some profiling in our codebase once we get to that point, and see how much wasted sCU we are doing.
If the data structure is immutable, such that it's either a pointer comparison or "check until first part of the data is different", isn't it faster than render + diff anyway?
Is it considered best practice to use the "key" of a child element to signify if it should rerender? This is what I've been doing and it seems to work well. If a parent updates its state, and then as a result, changes the props of some or all of its children, the parent sets the "key" of a child to effectively a hash of the props of that child.
Hey Ben! Could you speak to using stateless functional components vs PureComponent in terms of performance, especially now that Fiber is close? Which one would you use today?
how expensive are shallow === checks compared to re-rendering unnecessarily though? what advantages would stateless functional components offer above purecomponents?
This is actually a pretty decent article, in part because it signals its audience properly: (semi-?)experienced React developers who haven't dealt with optimization yet.
For some reason the focus is always on preventing re-rendering if it comes to optimising a React app. I understand that it can be really effective and is often the easy way out, but re-rendering in itself is not costly and I don't really care about it the most of the time.
I am more concerned that the code that runs during a re-render is not rebuilding huge static lists that never change and so. I see that over and over again in React apps. I tend to build a lot of the static stuff in the ComponentWillMount stage to prevent that. Only when already optimised code is getting to slow I start thinking about preventing re-rendering if possible.
My reason for not starting with ShouldComponentUpdate is that you have to be very careful not creating nasty bugs with that like I did some times. If a year later you write some code and it doesn't work for some reason it is painful if you find out after a long search that a stupid child component did not update for some prevention rule you forgot about. I really try hard to avoid premature optimisations.
That's a great point, and being aware of the dangers of shouldComponentUpdate is what this post is all about. There are a lot of gotchas when using PureComponents, and can lead to bugs if you're not careful.
Also, recalculating derived data (building static lists) in render() is very wasteful, and is also another gotcha when using PureComponents (object copying). Removing object copying from render() speeds up the actual render() call and allows you to take full advantage of PureComponents.
We are experimenting with ways to make all of this a bit easier, and hopefully will have some good news to share in Part 2 :)
Pretty good post, minus the advice to always use PureComponent everywhere (per Ben's comment in this thread).
If anyone's interested, my React/Redux links list has a large section of other articles on various React-related performance concerns, including benchmarking and optimization approaches: https://github.com/markerikson/react-redux-links/blob/master... .
> Fixing the issue is pretty simple*. We simply need to short circuit the re-rendering for a subtree if we know that the subtree hasn’t changed.
Not a frontend guy but I've seen this theme more than once on HN recently. It seems to me that addressing this anti-pattern would be built right in to modern React components. Isn't efficient DOM manipulation by pruning non-necessary changes kind of their thing?
It is, so a DOM change wouldn't occur, but in these cases you still go through a React rendering to virtual DOM phase (templating) and the DOM tree reconciliation.
Since these can be slow (although much faster than a DOM change), it makes sense to check and skip those steps when you can.
The focus of most of this article is how you can skip those steps when you're components input data is unchanged and common gotchas related to that.
But that sentence is talking about VirtualDOM rendering - which still takes time - not DOM manipulation.
Basically it's saying "if we don't need to do work, we shouldn't". Which React already does for DOM manipulation and this kind of optimization does it for virtualDOM creation.
React won't update the DOM when render returns the same result but if you can avoid those unnecessary render calls you save some scripting time. Front-end developers have to be very conservative when it comes to running JS code. Welcome to single threaded everything programming!
Along the same lines as the advice in TFA: If you pass an object literal as the `style` prop, it'll always re-render, because the object reference will change. Solution: instead of the object literal, pass a reference to an existing object.
One thing that has been bothering me is that React is slow by default. It re-renders everything every time unless you start looking into shouldComponentUpdate.
Even if I agree that premature optimization is the root of all evils, I like when the language and the framework I use make it writing fast code as easy as writing slow code.
I wonder if anybody has evaluated, the improvement they get in development speed using React when they add the time they have to spend to optimizing their React code.
In my experience, I am not even frustrated with React itself most of the time but with the other things in the ecosystem.
In our experience, React is not necessarily 'slow' by default. Re-constructing parts of the element tree each time can be a bit wasteful, but it is only as slow as your render() methods, and that is outside of React's control.
We have survived over 3 years with a massive application (over 2000 modules) and tons of wasteful re-rendering, but have only now started to notice any sluggishness. That makes React pretty fast in my mind.
Having said all that, we are experimenting with an 'all PureComponents' approach to potentially make React, but whether that turns out to be a good idea is yet to be seen (object comparisons in sCU are not free).
Hmm, my experience has been pretty much the opposite. Even without optimization, React's renders won't cause a DOM update unless there is something to diff - I can't say the same for jQuery or Angular 1.x. As well, being big on the "don't use it unless you need it" bandwagon I tend to wait until I see components and re-use in my code before I import React in the first place.
If the total re-render is occurring under 16.67ms (60fps) in a non-trivial use-case I'm usually fine leaving it as-is. Most render cycles taking longer than that involve operations on large data sets or events firing at the millisecond level (mouseover, drag, etc) - and those are worth fixing as they'll actually have noticeable impacts on the user experience. But I tend not to optimize just to pat myself on the back for "optimization".
From what I've found in my current job creating a js react app as well as side project with cljs is that advanced optimsation of js react === basic usage of clojurescript reagent.
I've found no redeeming features when developing the is app, issues with hot reloading and constant integration work to get everything to play nice with immutable js
Is there special logic in react that binds arguments of a function to the props with the same name? I'm talking about the handleDelete "fix" in the article:
I guess they just call that function from within the Data component with the correct parameter. But then, Data component needs to know how to call that function. Is there a better way?
> I guess they just call that function from within the Data component with the correct parameter.
Yep
> Is there a better way?
We're experimenting with some other options internally. Once we have a better sense of what works best, we will post another article on our learnings :)
I'm the author of CxJS[1] which uses React for rendering. Before rendering, the whole tree is scanned for data changes and with that information available shouldComponentUpdate is very simple.
Another technique that I find very useful is to use a dedicated data declaration component which then decides if children should update or not. Try grid sorting on this page:
https://worldoscope.cxjs.io/yyrsmjk
Yeah. That's exactly what I was thinking as I read through the list of gotchas.
We've just started using mobx ourselves. There's still a weird contention between events and state that I'm yet develop patterns for but overall I'm really happy with it.
I would generally say that there is a reciprocal relationship of performance and maintainable code, no matter what you use.
React is a powerful way to build your front-end, but it's power is in structure / code.
In my experience with React, fine-tuning components for faster rendering is always a pain. Too much magic happens behind the scenes and too difficult to keep that in mind while writing your beautiful components.
sophiebits|8 years ago
(I work on React.) This isn't quite right. If we recommended that PureComponent be used everywhere, it would probably be the default already. Rather -- the comparison to decide whether or not a component should be rerendered costs something, and in the case that you do want to rerender, all of the time spent checking whether you should have rerendered is wasted.
Instead, we'd suggest you be conscious of where you need to do the comparisons. It's usually only in a couple of places in your app. Good candidates are on the children of a long list or around large parts of the app that change independently (that is, cases where you know the parent should often rerender but the child shouldn't). A few well-placed shouldComponentUpdate (or PureComponent) uses can go a long way.
dmnd|8 years ago
When using immutable data structures the comparison in `shouldComponentUpdate` is very cheap. Assuming that, using pure components everywhere is very tempting for simplicity.
Correct me if I'm wrong, but React creates an object for every component to pass props around. Constructing that object is linear in the number of props. An additional `shouldComponentUpdate` check for each component is also linear in the number of props. So using pure components everywhere is at worst adjusting the constant.
Also, in a world where PureComponent is the default, perhaps React could monitor the "hit rate" of `shouldComponentUpdate` and decide to not call it if a component returns true too often?
dounan|8 years ago
As dmnd pointed out, I'm not entirely convinced that dropping PureComponent everywhere is not a good idea.
For our app specifically, we unfortunately do data loading in a lot of places, which means that there are quite a bit more than just few places that can benefit from being a PureComponent. Our current idea is to try to make everything a PureComponent, and go back and 'unpurify' the places that have wasteful sCU comparisons. This might not turn out to be a good idea though, for the reasons you mentioned.
I'll make sure to do some profiling in our codebase once we get to that point, and see how much wasted sCU we are doing.
continuational|8 years ago
rhinoceraptor|8 years ago
e.g.,
vschatmasta|8 years ago
o_____________o|8 years ago
> Instead, we'd suggest you be conscious of where you need to do the comparisons.
I'm not following, wouldn't that mean PureComponent by default and opt-in specialized checks when needed?
anotherfounder|8 years ago
ma_long_bay|8 years ago
diggan|8 years ago
mercer|8 years ago
bobsam|8 years ago
Edit: sorry guys, didn't knew you were all on HN :(
uranian|8 years ago
I am more concerned that the code that runs during a re-render is not rebuilding huge static lists that never change and so. I see that over and over again in React apps. I tend to build a lot of the static stuff in the ComponentWillMount stage to prevent that. Only when already optimised code is getting to slow I start thinking about preventing re-rendering if possible.
My reason for not starting with ShouldComponentUpdate is that you have to be very careful not creating nasty bugs with that like I did some times. If a year later you write some code and it doesn't work for some reason it is painful if you find out after a long search that a stupid child component did not update for some prevention rule you forgot about. I really try hard to avoid premature optimisations.
dounan|8 years ago
Also, recalculating derived data (building static lists) in render() is very wasteful, and is also another gotcha when using PureComponents (object copying). Removing object copying from render() speeds up the actual render() call and allows you to take full advantage of PureComponents.
We are experimenting with ways to make all of this a bit easier, and hopefully will have some good news to share in Part 2 :)
acemarke|8 years ago
If anyone's interested, my React/Redux links list has a large section of other articles on various React-related performance concerns, including benchmarking and optimization approaches: https://github.com/markerikson/react-redux-links/blob/master... .
metalliqaz|8 years ago
> Fixing the issue is pretty simple*. We simply need to short circuit the re-rendering for a subtree if we know that the subtree hasn’t changed.
Not a frontend guy but I've seen this theme more than once on HN recently. It seems to me that addressing this anti-pattern would be built right in to modern React components. Isn't efficient DOM manipulation by pruning non-necessary changes kind of their thing?
wcjordan|8 years ago
Since these can be slow (although much faster than a DOM change), it makes sense to check and skip those steps when you can.
The focus of most of this article is how you can skip those steps when you're components input data is unchanged and common gotchas related to that.
Some other great posts in this vein are: https://facebook.github.io/react/docs/optimizing-performance... and http://benchling.engineering/performance-engineering-with-re...
abritinthebay|8 years ago
But that sentence is talking about VirtualDOM rendering - which still takes time - not DOM manipulation.
Basically it's saying "if we don't need to do work, we shouldn't". Which React already does for DOM manipulation and this kind of optimization does it for virtualDOM creation.
msoad|8 years ago
robto|8 years ago
This is one place where using Clojurescript wrappers of React has a real payoff - immutable datastructures make equality checking very very cheap.
mendelk|8 years ago
ChrisCinelli|8 years ago
Even if I agree that premature optimization is the root of all evils, I like when the language and the framework I use make it writing fast code as easy as writing slow code.
I wonder if anybody has evaluated, the improvement they get in development speed using React when they add the time they have to spend to optimizing their React code.
In my experience, I am not even frustrated with React itself most of the time but with the other things in the ecosystem.
dounan|8 years ago
We have survived over 3 years with a massive application (over 2000 modules) and tons of wasteful re-rendering, but have only now started to notice any sluggishness. That makes React pretty fast in my mind.
Having said all that, we are experimenting with an 'all PureComponents' approach to potentially make React, but whether that turns out to be a good idea is yet to be seen (object comparisons in sCU are not free).
seangrogg|8 years ago
If the total re-render is occurring under 16.67ms (60fps) in a non-trivial use-case I'm usually fine leaving it as-is. Most render cycles taking longer than that involve operations on large data sets or events firing at the millisecond level (mouseover, drag, etc) - and those are worth fixing as they'll actually have noticeable impacts on the user experience. But I tend not to optimize just to pat myself on the back for "optimization".
joncampbelldev|8 years ago
joncampbelldev|8 years ago
positivecomment|8 years ago
nip|8 years ago
[1] https://facebook.github.io/react/docs/handling-events.html
[2] https://babeljs.io/docs/plugins/transform-class-properties/
dounan|8 years ago
Yep
> Is there a better way?
We're experimenting with some other options internally. Once we have a better sense of what works best, we will post another article on our learnings :)
unknown|8 years ago
[deleted]
kentor|8 years ago
zevyoura|8 years ago
mstijak|8 years ago
Another technique that I find very useful is to use a dedicated data declaration component which then decides if children should update or not. Try grid sorting on this page: https://worldoscope.cxjs.io/yyrsmjk
[1]: https://cxjs.io
wbc|8 years ago
aidos|8 years ago
We've just started using mobx ourselves. There's still a weird contention between events and state that I'm yet develop patterns for but overall I'm really happy with it.
drinchev|8 years ago
React is a powerful way to build your front-end, but it's power is in structure / code.
In my experience with React, fine-tuning components for faster rendering is always a pain. Too much magic happens behind the scenes and too difficult to keep that in mind while writing your beautiful components.
pvg|8 years ago
There isn't an inherent one, it's just that writing for both is much harder than just for one.
CCing|8 years ago
dounan|8 years ago
pawelwentpawel|8 years ago
dounan|8 years ago