You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Stateless functional components and shouldComponentUpdate #5677
In an ideal world, most of your components would be stateless functions because these stateless components can follow a faster code path within the React core. This is the recommended pattern, when possible.
This pattern is designed to encourage the creation of these simple components that should comprise large portions of your apps. In the future, we’ll also be able to make performance optimizations specific to these components by avoiding unnecessary checks and memory allocations.
What I find unclear is these explainations is how React optimize the rendering when using stateless functional components. The good sense would be that React uses something similar to shallowEqual to know if it has to call the function or not, but as React does not enforce strict immutability yet (I mean the PureRenderMixin is actually an option, not the default), I wonder how these functional components behave.
I think this should be better documented if any memoization technique is used when rendering these functional components, because it's not so obvious to me if my app will perform almost the same (or better) if I choose to replace all my components using PureRenderMixin and no state/lifecycle methods by functional components as I don't have much insights of the internal working of the optimizations done.
For complex components, defining shouldComponentUpdate (eg. pure render) will generally exceed the performance benefits of stateless components. The sentences in the docs are hinting at some future optimizations that we have planned, whereby we won't allocate an internal instance for stateless functional components (we will just call the function). We also might not keep holding the props, etc. Tiny optimizations. We don't talk about the details in the docs because the optimizations aren't actually implemented yet (stateless components open the doors to these optimizations).
Reacted by Nicholas, Morgan Cheng, Ivan Babak, Rom, Volkan Özçelik, Mark Penner, Corey McDaniel, Philip Chung, Diego Anaya, Randy Creasi and 13 more
Reacted by Qwerty (Vítězslav Ackermann Ferko) and Dominik Dosoudil
So what I understand is that currently functional components do not memoize their execution based on shallowCompare of props right? Couldn't it be implemented easily?
Reacted by Ian Channing, Ermolay Romanov and Kongfujonstew
Correct. Such memoization would break any application that was not using immutable data, because the "optimization" would be making an assumption that the root prop reference changes when the data changes. Imagine that the prop is an array, pushing to the array would not show up in a shallowCompare, which is why that optimization is not valid by default.
So how can I use that memoization with a functional component? Will I be able to do so in the future?
I guess I could wrap it in an HOC but this then probably defeats the purpose of using functional components for the coming little optimizations that can be done
There are discussions about having a pureRender flag that you could set on the function, or allowing it to participate in the shouldUpdate lifecycle, but that's currently not implemented. At the moment, stateless functions can not be pure-render.
It is worth keeping in mind that sometimes people abuse/overuse pure-render; it can sometimes be as or more expensive than running the render again, because you're iterating over the array of props and potentially doing things like string compares, which is just extra work for components that ultimately return true and then proceed to rerender anyway. PureRender / shouldComponentUpdate really is considered an escape hatch for performance and is not necessarily something that should be blindly applied to every component.
Reacted by Song Seunggeun, Ivan Babak, Will Douglas, Eugene Mirotin, Boris Yankov, Eric Fennell, Jack Zhang, Yann Brelière, marcus-magnusson, Augustus Yuan and 25 more
yes I understand that however in most cases where we start to compare primitive values there's generally a parent that may already have memoized the rendering. It's often the data is coming from an API or is stored in objects so your primitives are probably in an immutable object at first before being dispatched to deeper components, thus giving the dispatcher parent to block rendering.
I think in ELM or Om this is applied by default to all the tree and works pretty well.
Is it that bad to compare strings vs comparing object identities? I guess strings hashes are compared first no?
Elm and Om are both far more functional/immutable than general javascript, which is probably why it makes more sense there. We are supporting standard javascript as a target language, and javascript is a language where mutability is common.
My perf benchmarks have found string compares to sometimes be quite slow (just doing string-compares of the prop-names with pre-defined values that we need to handle specially, and that isn't even arbitrarily long data compares). Hash comparison can only detect miss-matches, but can not guarantee that two strings are equal (due to collisions), so to prove equality you still need to walk the whole string, but your assumption is that the two strings are equal in the common case, otherwise why would you be using pure-render (ie. with hashing, you still need to walk the whole string in the supposed common case). String pooling does a better job than hashing, but it starts to get complicated.
Anyway, we digress. The simple answer is: no, we don't do pure render by default, but we may provide a way for you to opt-in in the future.
Reacted by Yann Brelière, Corey McDaniel, Peter Leonov, Eric Elliott and Paul "Joey" Clark
I don't know so much about the javascript's inner working but coming from Java world we have string pooling built-in so I may assume wrong things about js :)
I also come from a Java background. Java's pooling works pretty well, but you still can't depend on str1 == str2 in Java, for exactly the reason that pooling is not guaranteed by the JVM because "it starts to get complicated".
Interesting read. I assumed functional components would be "pure render" by default when seeing the syntax and reading the blog post about 0.14.
Reacted by András Polgár, Emil Ahlbäck, Asa Ayers, Turadg Aleahmad, Alexander Kuzmin, Song Seunggeun, Gajus Kuizinas, Timofey Lugovoy, Oliver Turner, Ivan Babak and 65 more
I'm going to close this out, since it was mostly a discussion thread and there is nothing actionable here.
Reacted by Jon Vuri, Andy Noelker, Mariano Desanze, Adam Faryna, Zack Young, Sergey Zarovskiy, Dinh Tran, Remco Bloemen, Cristian Eriomenco, swarthy and 16 more
Reacted by Ivan Babak, Karthika Ramachandran, Nam Wook Kim, Jarrod Mosen, Reslav Hollós, swarthy, Furkan Tunalı, Qwerty (Vítězslav Ackermann Ferko) and Amir Irani
Hi, the action that I think should be here is memoization by default of stateless functions of React.
Here is an example of doing it manually - notice the diffs in the console.log...: https://jsfiddle.net/giltig/a6ehwonv/28/
Reacted by Morgan Cheng, Javier Valencia, AMAGI / Jun Yuri, Katsuma Ito, Louis DeScioli, Ricardo Medina, Craig Richardson-Binks, Eugene Tolmachev, Remco Bloemen, kiho and 8 more
Is there any sort of rule of thumb for react being quicker for a component to render with many stateless functions or many classes with shouldComponentUpdate shallow equals.
Or is it something that needs to be profiled for every use case?
In my case there is many small components that are very small and are constantly mounted and unmounted.
I assume there will massive perf savings in mounting / unmounting for stateless because there is no lifecycle ?
I started working at this small library that may be helpful in such situations. https://github.com/msuperina/react-cache
It is definitely just a start as there may be many more optimizations to do.
It's surprising that functional components are not PureComponent by default...
Reacted by Tom Esterez, Friedel Ziegelmayer, Paweł Rutkowski, Johan Berling, MT Lewis, Michael, Abraham Alcaina, Daniel Earwicker, sean, Javier Candalaft and 31 more
It's surprising that functional component not PureComponent by default...
Although it's somewhat counter-intuitive, I think it actually makes sense that functional components are not PureComponent by default. The only guarantee (correct me if I'm wrong) React has with functional components that it doesn't have with class-based is that they don't have any internal state. People could still be mutating their props in the wild and relying on their components to re-render, making this a breaking change. (I agree, however, that there should be some way to opt-in to this behavior in the interim.)
Above it is mentioned that in the future there might be a way to opt-in to pure functional components. Is there an issue I can follow to see the progress on this? I've found this issue but it is closed so I guess there is no point to follow along here.
Btw, if such and option would be implemented, I think it would be nice if it could be applied at a global level rather than having to set it on every function.
Reacted by miketamis, Dmitrii, Sudhakar and Scott BonAmi
Recompose.pure is simply a wrapper around React's Component and shallowEqual. Wondering what's the benefit of using that vs just extending Component/PureComponent (and avoid packing extra pounds).
My perf benchmarks have found string compares to sometimes be quite slow (just doing string-compares of the prop-names with pre-defined values that we need to handle specially, and that isn't even arbitrarily long data compares).
Sorry, I had to explain.
Hooks can't cancel update like memo can. You can't use Hooks to control render. Can you provide an example?
For memo it's simple:
Hooks can't cancel update like memo can. You can't use Hooks to control render. Can you provide an example?
Sure you can. In fact, hooks can go beyond React.Memo in some use-cases. React.Memo avoids (or cancels as you call it) updates by doing a "shallow" compare of the props. In that sense, it'll fail to prevent the update if you use deep objects or objects that have function refs. Hooks can help you in those cases as well.
First of all, if you have shallow components, the simple useState hook can help you avoid re-renders.
Secondly, if you have nested parent/child structure and you want to avoid child re-renders on parent update, there is useMemo which lets you memoize the renders:
This is equivalent to shouldComponentUpdate where your component will only render if a or b has changed (or whatever props you pass in the 2nd argument array).
Then there's useCallback hook that lets you keep the same function ref so SCU works.
Finally there's useReducer hook that let's you deal with deep objects.
I'm not saying no one should use React.memo (as useMemo and hooks in general have some constraints where React.memo might be a better choice) rather trying to highlight the fact that we now have more options and choices in our toolbelt.
Reacted by Yann Brelière, mqklin, WangBiaoxuan, Chris Wingler, 이준형 · Gompro, nomastickles, Gragog, Daniel Klimuntowski, Igor and Tony Jiménez
Activity
jimfb commentedon Dec 16, 2015
For complex components, defining
shouldComponentUpdate(eg. pure render) will generally exceed the performance benefits of stateless components. The sentences in the docs are hinting at some future optimizations that we have planned, whereby we won't allocate an internal instance for stateless functional components (we will just call the function). We also might not keep holding the props, etc. Tiny optimizations. We don't talk about the details in the docs because the optimizations aren't actually implemented yet (stateless components open the doors to these optimizations).slorber commentedon Dec 17, 2015
Thanks
So what I understand is that currently functional components do not memoize their execution based on shallowCompare of props right? Couldn't it be implemented easily?
jimfb commentedon Dec 17, 2015
Correct. Such memoization would break any application that was not using immutable data, because the "optimization" would be making an assumption that the root prop reference changes when the data changes. Imagine that the prop is an array, pushing to the array would not show up in a shallowCompare, which is why that optimization is not valid by default.
slorber commentedon Dec 17, 2015
So how can I use that memoization with a functional component? Will I be able to do so in the future?
I guess I could wrap it in an HOC but this then probably defeats the purpose of using functional components for the coming little optimizations that can be done
jimfb commentedon Dec 17, 2015
There are discussions about having a
pureRenderflag that you could set on the function, or allowing it to participate in the shouldUpdate lifecycle, but that's currently not implemented. At the moment, stateless functions can not be pure-render.It is worth keeping in mind that sometimes people abuse/overuse pure-render; it can sometimes be as or more expensive than running the render again, because you're iterating over the array of props and potentially doing things like string compares, which is just extra work for components that ultimately return true and then proceed to rerender anyway. PureRender /
shouldComponentUpdatereally is considered an escape hatch for performance and is not necessarily something that should be blindly applied to every component.slorber commentedon Dec 17, 2015
I would be happy to have that flag.
yes I understand that however in most cases where we start to compare primitive values there's generally a parent that may already have memoized the rendering. It's often the data is coming from an API or is stored in objects so your primitives are probably in an immutable object at first before being dispatched to deeper components, thus giving the dispatcher parent to block rendering.
I think in ELM or Om this is applied by default to all the tree and works pretty well.
Is it that bad to compare strings vs comparing object identities? I guess strings hashes are compared first no?
jimfb commentedon Dec 17, 2015
Elm and Om are both far more functional/immutable than general javascript, which is probably why it makes more sense there. We are supporting standard javascript as a target language, and javascript is a language where mutability is common.
My perf benchmarks have found string compares to sometimes be quite slow (just doing string-compares of the prop-names with pre-defined values that we need to handle specially, and that isn't even arbitrarily long data compares). Hash comparison can only detect miss-matches, but can not guarantee that two strings are equal (due to collisions), so to prove equality you still need to walk the whole string, but your assumption is that the two strings are equal in the common case, otherwise why would you be using pure-render (ie. with hashing, you still need to walk the whole string in the supposed common case). String pooling does a better job than hashing, but it starts to get complicated.
Anyway, we digress. The simple answer is: no, we don't do pure render by default, but we may provide a way for you to opt-in in the future.
slorber commentedon Dec 17, 2015
so this is fine :)
I don't know so much about the javascript's inner working but coming from Java world we have string pooling built-in so I may assume wrong things about js :)
jimfb commentedon Dec 17, 2015
I also come from a Java background. Java's pooling works pretty well, but you still can't depend on
str1 == str2in Java, for exactly the reason that pooling is not guaranteed by the JVM because "it starts to get complicated".tjconcept commentedon Jan 8, 2016
Interesting read. I assumed functional components would be "pure render" by default when seeing the syntax and reading the blog post about 0.14.
jimfb commentedon Jan 8, 2016
I'm going to close this out, since it was mostly a discussion thread and there is nothing actionable here.
giltig commentedon Jan 18, 2016
Hi, the action that I think should be here is memoization by default of stateless functions of React.
Here is an example of doing it manually - notice the diffs in the console.log...:
https://jsfiddle.net/giltig/a6ehwonv/28/
idrm commentedon Jun 21, 2016
@giltig, Your memoization function will not work as intended when there are multiple instances of the same component with different properties.
jooj123 commentedon Aug 20, 2016
Is there any sort of rule of thumb for react being quicker for a component to render with many stateless functions or many classes with shouldComponentUpdate shallow equals.
Or is it something that needs to be profiled for every use case?
In my case there is many small components that are very small and are constantly mounted and unmounted.
I assume there will massive perf savings in mounting / unmounting for stateless because there is no lifecycle ?
14 remaining items
Klaasvaak commentedon Mar 30, 2017
@davidworkman9 was looking at this code here: https://github.com/facebook/react/blob/v15.4.2/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js#L70 and thought that it might work. But I guess it doesn't
msuperina commentedon Apr 10, 2017
I started working at this small library that may be helpful in such situations.
https://github.com/msuperina/react-cache
It is definitely just a start as there may be many more optimizations to do.
Huxpro commentedon Jun 21, 2017
It's surprising that functional components are not
PureComponentby default...a8568730 commentedon Jul 21, 2017
I wrap my functional components with Recompose.pure.
Codepen
felquis commentedon Jul 31, 2017
I improved @davidworkman9's example #5677 (comment) ... here -> https://jsfiddle.net/tynt7te9/ and updated to 15.6.1
I realized the best thing to do is to use:
https://jsfiddle.net/tynt7te9/1/ pretty cool
danny-andrews commentedon Sep 27, 2017
Although it's somewhat counter-intuitive, I think it actually makes sense that functional components are not
PureComponentby default. The only guarantee (correct me if I'm wrong) React has with functional components that it doesn't have with class-based is that they don't have any internal state. People could still be mutating their props in the wild and relying on their components to re-render, making this a breaking change. (I agree, however, that there should be some way to opt-in to this behavior in the interim.)jonaskello commentedon Apr 5, 2018
Above it is mentioned that in the future there might be a way to opt-in to pure functional components. Is there an issue I can follow to see the progress on this? I've found this issue but it is closed so I guess there is no point to follow along here.
Btw, if such and option would be implemented, I think it would be nice if it could be applied at a global level rather than having to set it on every function.
mrchief commentedon Apr 13, 2018
Recompose.pureis simply a wrapper around React'sComponentandshallowEqual. Wondering what's the benefit of using that vs just extendingComponent/PureComponent(and avoid packing extra pounds).danny-andrews commentedon Jul 13, 2018
@jimfb Can you share this benchmark? Maybe things have changed since 2015, but it appears string comparison is quite fast, and the most JS implementations use string interning. https://stackoverflow.com/questions/5276915/do-common-javascript-implementations-use-string-interning
skipjack commentedon Jan 11, 2019
For anyone who's still stumbling on this,
React.memowas released recently which is an easy built-in way to create a pure, stateless component:https://reactjs.org/docs/react-api.html#reactmemo
mrchief commentedon Jan 11, 2019
Better than memo, what you're looking for is React hooks
mqklin commentedon Feb 7, 2019
@mrchief you can't use Hooks to solve this problem
mrchief commentedon Feb 7, 2019
@mqklin Why do you say that? I'm going based on the OP, maybe I missed something down the thread?
mqklin commentedon Feb 8, 2019
Sorry, I had to explain.
Hooks can't cancel update like
memocan. You can't use Hooks to control render. Can you provide an example?For
memoit's simple:mrchief commentedon Feb 8, 2019
Sure you can. In fact, hooks can go beyond
React.Memoin some use-cases.React.Memoavoids (or cancels as you call it) updates by doing a "shallow" compare of the props. In that sense, it'll fail to prevent the update if you use deep objects or objects that have function refs. Hooks can help you in those cases as well.First of all, if you have shallow components, the simple
useStatehook can help you avoid re-renders.Secondly, if you have nested parent/child structure and you want to avoid child re-renders on parent update, there is
useMemowhich lets you memoize the renders:This is equivalent to
shouldComponentUpdatewhere your component will only render ifaorbhas changed (or whatever props you pass in the 2nd argument array).Then there's
useCallbackhook that lets you keep the same function ref so SCU works.Finally there's
useReducerhook that let's you deal with deep objects.You can find all of this info in the FAQs; specifically in How do I implement shouldComponentUpdate? and Are Hooks slow because of creating functions in render?.
I'm not saying no one should use
React.memo(asuseMemoand hooks in general have some constraints whereReact.memomight be a better choice) rather trying to highlight the fact that we now have more options and choices in our toolbelt.