-
Notifications
You must be signed in to change notification settings - Fork 47k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Stateless functional components and shouldComponentUpdate #5677
Comments
For complex components, defining |
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? |
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 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 / |
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? |
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. |
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 :) |
I also come from a Java background. Java's pooling works pretty well, but you still can't depend on |
Interesting read. I assumed functional components would be "pure render" by default when seeing the syntax and reading the blog post about 0.14. |
I'm going to close this out, since it was mostly a discussion thread and there is nothing actionable here. |
Hi, the action that I think should be here is memoization by default of stateless functions of React. |
@giltig, Your memoization function will not work as intended when there are multiple instances of the same component with different properties. |
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. 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 ? |
There are currently no special optimizations done for functions, although we might add such optimizations in the future. But for now, they perform exactly as classes. |
fair enough - after running through parts of the react source, i can see that stateless functions still mount like regular classes |
@idrm Hi, but that's all the point. Memoization works when you give the component the same props which is exactly what we want, so it will only trigger render for components who receives different props thus getting pure rendering for stateless components as well (without shouldComponentUpdate) |
So should we memoize or is it already done in react code? On Sun, 21 Aug 2016 19:53 giltig, notifications@github.com wrote:
|
There is a library |
@giltig, what I'm saying is that your memoization function (purify) is, essentially, a component instance cache with a bucket size of 1 per "purified" component. I don't see how a memoize approach can become a substitute for shouldComponentUpdate the way React currently works. |
I'm new to React, so I welcome any correction/explanation, but I think you'd want to include a defaultProps assignment in your pure() function:
Also, as a tangent, is this basically the HOC wrap approach that slorber mentioned, earlier? |
You shouldn't use |
Should this do the trick?
|
To sum up the discussion... The current state is that functional components are always re-rendered even if props are unchanged, right? How is that different from non-functional components? Correct me if I'm wrong but my understanding is that React does not compare props or state itself unless you provide |
Correct.
You can provide a |
Looks like it doesn't. https://jsfiddle.net/a6ehwonv/92/ |
@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 |
I started working at this small library that may be helpful in such situations. |
It's surprising that functional components are not |
I wrap my functional components with Recompose.pure.
|
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: class PureComponent extends React.PureComponent {
render () {
console.count('PureComponent')
return <div>React.PureComponent: {this.props.render}</div>
}
shouldComponentUpdate: false
} https://jsfiddle.net/tynt7te9/1/ pretty cool |
Although it's somewhat counter-intuitive, I think it actually makes sense that functional components are not |
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. |
|
@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 |
For anyone who's still stumbling on this, |
Better than memo, what you're looking for is React hooks |
@mrchief you can't use Hooks to solve this problem |
@mqklin Why do you say that? I'm going based on the OP, maybe I missed something down the thread? |
Sorry, I had to explain.
|
Sure you can. In fact, hooks can go beyond First of all, if you have shallow components, the simple Secondly, if you have nested parent/child structure and you want to avoid child re-renders on parent update, there is
This is equivalent to Then there's Finally there's 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 |
This is probably a question / documentation issue.
In some places of the doc we can read:
https://facebook.github.io/react/docs/reusable-components.html
https://facebook.github.io/react/blog/2015/10/07/react-v0.14.html
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.
The text was updated successfully, but these errors were encountered: