-
Notifications
You must be signed in to change notification settings - Fork 557
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
React.memo() #63
React.memo() #63
Conversation
This is a great idea, I do think the name |
The argument name doesn't matter, it's not technically a part of the API. We can call it |
I very have the same doubt about naming of the second function argument |
@gaearon the name also will be shown in TypeScript autocomplete features |
Note that this is the same API as recompose/pure (except for the optional second argument, although recompose has several other functions to provide similar functionality). I can’t comment much on implementation, but it’s hard to imagine a more clear or convenient API. I use recompose heavily, declaring all my components as functions and adding state, lifecycle methods, etc. with recompose’s HOCs. I effectively treat this pattern as the missing unification of class and functional components, by never defining class components or working with them directly. It works remarkably well, and could be a great direction for React. React already sneaks in concepts from functional programming, and this would be a big escalation of that wonderful trend. :) https://github.com/acdlite/recompose/blob/master/docs/API.md#pure |
You defined the second parameter to only be a function, I would personally choose an object as it is more future proof and allows for more customization later on, eg. implementing life cycle methods that change props here. Just as an example, I do not want to derail the conversation:
However using an object does come with a small performance decrease. PS: Silly me always assumed that function where pure by default. |
What if component always stays the same, it would simply have a Non-pure component: const Message = () => <div>Hello world</div>; Pure component: const Message = () => <div>Hello world</div>;
Message.shouldComponentUpdate = React.notShallowEqual;
React.pure = (component, comparator = React.notShallowEqual) => {
component.shouldComponentUpdate = comparator;
}; |
This introduces an extra runtime property check for every single function component, making the whole app slower and potentially causing deoptimizations. This design was considered (see "Alternatives") and rejected.
There are no plans for making this function more advanced as it would defeat the optimizations it's supposed to provide. |
For clarification, is this RFC about the addition of the second optional argument? I thought this PR meant that in a future release we would have a pure function: https://github.com/facebook/react/pull/13748/files |
The shouldComponentUpdate property also mutates the functional component, which means couldn’t easily export the original component and a pure version. |
This is an RFC covering that PR. We've merged it to test it at FB but now we're getting closer to an open source release and want to get community feedback. |
I would vote for the breaking change. I would even almost like this to be the case for Component (i.e. get rid of PureComponent and just make shallow compare the default) and instead of making code which works well when mutable, make it so that if you mutate props or state that you get bugs right away instead of in 3 months time when the code has solidified. This would really suck for new devs, but could help drive home the idea of immutability and pure funcs. oh and good luck with migrating the millions of facebook Components, I don't think a codemod would fix immutability bugs. Edit: I really don't think this could or would happen, it's more I wish that React tried to push for immutability more |
I think the second argument should be the ”same” as To do the opposite (presumably because you just want to put Unless I'm missing something... |
It wouldn't be just bad because it's a breaking change. It would also be worse because:
|
This would introduce a hefty performance fine in many cases
I'm a fan of "learn by pain", but the downsides are way too big to introduce this breaking change. Your comment regarding the internal Facebook components actually makes me think you're a troll. |
Would be nice if the second argument was called
|
@Nimelrian almost certainly he's not trolling. He's saying, if you did go with the breaking change, good luck updating. It's a bit of happy sarcasm that I think you've misinterpreted. |
Why |
@Nimelrian no not a troll. I used facebook as an example of how this wouldn't work because I am well aware that given their amount of components that they would struggle to support this as their usual strategy for breaking changes are codemods. It's unrealistic to expect facebook or even more so, the world to be able to handle such a drastic change like that without way too much pain. tbh my comment was pointless given it's just not feasible to do something as drastic as that, so I really shouldn't have left any more feedback other than I would prefer the default behaviour to be shallow compare. However it's just not something that i see actually having enough net positive. |
Ok I'm glad I'm not the only one thinking it should be shouldUpdate not are same. I'll go further and say what I wanted to say originally now I know I'm not crazy - unless there's some particular technical objection to it, it's an absolute no-brainer that it should have |
What i love the most about react's naming stuff in API is that its telling us what is the Purpose of the function / parameter, rather than what it Does (implementation details?). Same goes for |
@falconmick Than I misread your comment, sorry! |
This API seems like it enables making third-party components pure. What would be the behavior if you passed an already pure component to // I don't know if Button is already using React.pure
import {Button} from 'third-party'
import {pure} from 'react'
// Noop? Error?
export default pure(Button); Following that thread, what happens if you pass a class component? Can users safely apply |
How about |
This looks great! What would be current advice of when to use this and when not to? Is this generally a good default or often preoptimization? |
We are already checking
I'm struggling to see how this concern is relevant here, maybe you can provide an example? |
Using |
Ah, yes, naming conflicts. That makes sense. 👍
That makes sense as well. 👍 Thank you for explaining! This is quite the challenge. 😄 |
text/0000-memo.md
Outdated
|
||
`React.memo` returns a component type that tells React "render the inner type, but bail out on updates if props are shallowly equal". In other words, the rendering result is memoized. The prop comparison function can be specified as a second argument to `React.memo`. | ||
|
||
`React.memo` only accepts function components as the first argument. It doesn't accept classes since those can extend `PureComponent` directly, and mixing the two approaches is confusing. `React.memo` is intended to be applied at the definition site. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
React.memo
only accepts function components as the first argument.
How does this work with React.forwardRef
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would this |
@theKashey memoizing between requests could run the risk of caching and leaking stale user data. |
@aweary not if it's pure. That's basically the entire point of memorisation... |
@tomhicks It's still possible if a component in the cached subtree reads data from an external source. Most server-rendered apps do a full render at the top level anyways, which makes this a moot point. The API would have to also consider other aspects of caching (where does cached data get stored?), which seems outside the scope of this RFC. |
How does it compare performance-wise to wrapping SFC in a PureComponent? Is it using PureComponent under the hood or is it more optimized? |
@aweary in that case it's not pure. I realise that this is probably academic and your real-wotld example is probably more helpful, but just sayin' |
If so, the
Because any 3rd party library could use the name |
My request is that code example include how to wrap around a redux-connected component or how to compose with other HOC libraries. I'd say being able to pass an equality function down is great but it would be great if the code examples included an implementation example. Also, would be great if the examples showed an example of where shallow equality will fail.
|
This is fair but you can also think it's short for "memoizing component" or something like this. In practice I don't think it's a problem. Take "props". It also has a completely different meaning in English. :-) React uses it as short for "properties". Or take "render". React doesn't actually render during the "render" function! So I understand why it might seem a bit odd at first. But another important consideration is to make it feel "light". This is an optimization API, and it shouldn't feel like a hassle to type. It's weird but that's how people think about APIs. Shorter words "feel" lighter which is what we want to express here. So we think "memo" will work fine. |
I feel changing the name to memo is very good approach, but what problem I see is that from now we will have two the same purpose concepts - PureComponent and memo, where their naming give a feeling that we deal with totally different things. This can be very misleading. Following this, my question is - does React team have a plan to change PureComponent name ( MemoComponent ... oh dont thing so ) or totally deprecate it, as I don't see a place for extending if we can compose by memo HOC. |
Not immediately but it's plausible that in the longer term |
We decided to allow to pass any component type to |
View formatted RFC
Note: I just wrote up the RFC. The semantics are designed by @sebmarkbage and @acdlite.