-
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
Q: When should you NOT use React memo? #14463
Comments
I would assume that the same general advice applies for |
I would also imagine it'd apply to the The main thing I'm interested in relating to this question is about the cost of class initialisation (and similar) - It's something that I see just dropped in in couple of places of the React docs by Facebook, without any evidence or references. I'm not challenging Facebook, but I'd love to read more about it, so I can know what they clearly do, and thus optimize my builds. They do the same with hooks, where they state:
Which is the first I've heard of classes messing with hot reloading - in my experience I've not actually ever had a working hot reloading system that actually does swap out small chunks of code. That could be b/c I use classes everywhere, but I've never in my readings come across anything saying 'classes are screwing up my hot reloading' or 'hey classes cost you ~5kb more than functional components'. I think a big factor in the answer on when to use From what I remember, it's something like " does not create a whole new element everytime - thats why mount methods & constructors don't get called every render. Instead, React does some magic to somehow re-use or compare the instance if it exists". This could be completely wrong or muddled, but that's also kind of my point. I'm not trying to derail this issue at all (And I do apologize for my ramblings in this comment), but I do feel it'd be nice to have some clear cut examples and discussion about where it's costing you (and saving you) to |
I'm not sure what "class initialization" has to do with Classes definitely make hot reloading more difficult, because of trying to swap out prototypes and stuff. I'm not clear on all the nitty-gritty details, but look through the https://github.com/gaearon/react-hot-loader repo to see all the complexities involved. Overall, the React team has frequently emphasized on social media that "wrapping everything in a As far as I know, everything in https://reactjs.org/docs/optimizing-performance.html that relates to You might also want to read some of the articles on optimizing React performance that I have listed at https://github.com/markerikson/react-redux-links/blob/master/react-performance.md . |
You're completely right - that was me being stupid. I've been working too hard lately, and it's left my brain in a muddle 😬
(I actually technically mean instancing - sorry about the confusion) In the hooks FAQ, they have the question Are Hooks slow because of creating functions in render?
For Facebook to say "the cost of creating class instances" implies to me there is a cost worth mentioning (i.e, compared to the cost of doing something like I'm assuming that the cost is actually one React suffers with classes due to how it works, where the cost is only a factor when you're creating lots of class instances in the space of seconds all the time, but again, this isn't something I recall seeing explored or talked about in detail in the rest of the React documents. Thanks for the links - I've not encountered them before, despite my best efforts 😕 You've given me some good reading to do! |
In React 15 and earlier, function components were wrapped in classes internally, so there was no real difference in perf behavior. In React 16, function components are now handled separately, with no class wrapping them. This means there's less overhead to rendering a function component overall than for a class component. References:
So, in general, an app that consistently renders N function components should take less total time to render than an app that renders N class components. How much less, I have no idea - you'd have to benchmark things. However, all of that is mostly separate from the original question of "when should I use I understood what you meant by "class initialization" - the cost of creating a single instance of a given class component, because you're rendering it for the first time. My point is that that has nothing to do with use of Also, that hooks FAQ entry is largely there because of the longstanding fear and confusion in the React community over "creating functions in render being bad for performance". See Ryan Florence's post React, Inline Functions, and Performance for thoughts on that topic. |
Can someone please explain (like I'm 5) WHY it's a bad idea to wrap all components in React.memo? If the props on a component haven't changed then it shouldn't re-render as it will simply be returning the exact same component as the initial render. I also don't understand why the react docs say For example, on my main index page I include a |
Components that receive other components through props shouldn't be pure (and by extend, use the memo HOC). See this for more info: facebook/react#14463
|
Here's the best info I've found on this. Seems like there are few cases where you wouldn't want to use Perhaps your parent component rerenders regularly and your child component does something impure like render the current time or fetch some data... though I'd think hooks would cover both of those well. |
Regarding when to use React.memo(), I wrote an interesting blog post. Check it out. I use the following rule of thumb:
|
I always use PureComponent for class based components. It's easy, and it just works. I've noticed that if I don't wrap basically all my components in memo(), nothing gets optimized. And since children are part of props, I had a rouge non-memoized component that cause everything to re-render(). I'm trying to like hooks, and some of them are useful, but the mental overhead is actually large. Ract.memo(), useCallback(), useState(), useRef(), useMemo(), useContext(), all used together in a < 100 line fine gets a bit hard to read. An example I've created to optimize dragging, which has a hooks version and a class version: https://github.com/mikeaustin/optimized-drag/tree/master/src |
It’d be great if there was a helper to let you diff everything except for children, and have React handle diffing Children. |
If you really, really want it... You could technically put the children into
It's just going to pollute that |
Let us say that we have a case like this one:
Does it worth to create a memoized functional component when it has an additional function? Does that additional function also get memoized, or in that case I would be slowing down things by creating a new function on every render? In this example, would be better to move on to a class-based component? |
I think you need to use 'useCallback' to memoize the extra function, pajarito. |
@Bohmaster I think he is not using What do you think ? |
@syntaxbliss Perhaps a bit more clear statement is: the resulting ReactElement/JSX element, to which your inner I would not care about function creation cost in render for Maybe this answer also helps to decide, if |
I'm just guessing based on what I know, but since not everyone using React embraces immutability, there might be cases where someone passes As soon as you memoise that The other potential downside of |
@StoneCypher @fbartho @mikeaustin @marcelkalveram @gaearon @rlesniak @sunny @panzerdp You should always use
|
Prove your arguments, or the whole community will see that you, you could not win the PUBLIC COURT, and cowardly put dislikes. WHAT EXACTLY arguments COULD you counter my arguments? WE as the whole React community listen to your counterarguments =)) Let's laugh right now =) we listen to your arguments |
Please stop tagging me |
@StoneCypher @fbartho @mikeaustin @marcelkalveram @gaearon @rlesniak @sunny @panzerdp But I want to teach you the truth)! I don't want you to live in misconceptions about React.memo, why don't I hear gratitude, but get dislikes? I sat, wrote, explained, tried, did you all GOOD. And he did not A SINGLE EVIL. And you are NOT GRATEFUL to me FOR GOOD, but you are doing EVIL: put dislikes. Why are you FOR GOOD - answer with EVIL? are you just -- EVIL???? |
Please stop tagging me too, I was never in the conversation in the first place. |
@sunny strange, apparently this is a GitHub bug |
@MaxmaxmaximusAWS please stop tagging people in this thread. |
This comment has been minimized.
This comment has been minimized.
To be honest, I would actually like to hear another opinion on what Mr. Maxmaxmaximus wrote in his first message (all trolling and jokes aside). It actually makes sense that comparing couple of props shallowly should consume less resources than executing the render function with all the hooks in it and building the JSX for the component (and all the sub-components). Strong/strict comparison (===) is a very simple operation. Also, could you explain to me, will React always compare entire virtual DOM trees or only the parts that actually changed? So if I exclude the part of the virtual DOM tree using Thank you! |
No trolling as you requested =) |
Again, please stop mentioning me… |
Considering that several people have asked you to stop tagging them and that your comments have been tagged as disruptive, I'd wager you are the one with inappropriate, irrational behavior.
I've blocked you. This is the first time in 12 years of GitHub that've had to do that… Please listen to what people are telling you and act more professionally. |
I want to point out that from my experience, people often fall into one of the following three categories:
All of them usually forget to memorize some super important component here and there (the website's Sometimes these places render many components, have logic and side effects. Sometimes they are rendered very often. I think the biggest benefit of making everything pure is "keeping it simple" by removing this feature altogether, even though, in some cases, it would make the application a little slower. |
@vzaidman function MyComponent(props) {
/* ender using props */
}
function areEqual(prevProps, nextProps) {
/*
returns true if nextProps renders
the same result as prevProps,
otherwise returns false
*/
return prevProps.style.width === nextProps.style.width
// or like this:
return JSON.stringify(prevProps.style) === JSON.stringify(nextProps.style)
}
export default React.memo(MyComponent, areEqual); |
This would be an overkill in 99% of cases and also hard to make sure you will not get some kind of onClick={() => and then the whole nice style comparison is useless |
People should use const [state, setState] = useState()
setState // it is actually memorized callback if we use const [state, setState] = useState()
useEffect(() => {
setState(true)
}, [setState]) // this dependency never will not changed in theory, our entire application should be wrapped in React.memo with correct props comparison settings, and use ʻuseCallback` for callbacks. then the reactivity atom will be optimized as much as possible, and the react will render ONLY what could really change. our application is speeding up by using a lot of memory. You can even write an extension in babel that automatically memorizes all callbacks, but I'm not a fan of "magic". |
Due to violations of our code of conduct, we are putting a temporary block on the user @MaxmaxmaximusAWS for two weeks. |
Shouldn't Well, I guess pipe operator |
@KurtGokhan the question has been asked repeatedly, in many places :) and my answer at the very top of this thread still applies. There are a number of cases where components will never memoize because the inputs are always changing, so applying it as a default blindly is not the right approach. Also see my additional thoughts here, with some quotes from Dan: |
Sorry for resurrecting this thread @markerikson. Just wanted to confirm if this is ever planned in the future. To me it seems like not using memo is more prone to performance issues. Especially when you realize that a state change in your root component will cause entire tree to re-render if you don't memo at all. But maybe that just sounds scary and it is actually not that bad. When asked this question, most people emphasize that it is prone to bugs caused by mutable state (which is arguably not the intended way to use React). I now understand that there can also be performance hits by blindly using memo. |
Hello @markerikson Even when you add children to the component with memo, the worst case performance will be the same https://codesandbox.io/s/react-memo-benchmark-m2bk6?file=/src/App.js |
…ches (#110) SearchBar requires multiple re-renders due to useEffect call in useRecentSearches to setup RecentSearches instance. The changes in this pr ensures a RecentSearches is set on the first render and only re-render if there is an update to `recentSearchesLimit`. Findings when attempt to memoize hooks and testing in SearchBar: Just using `useCallback` and `useMemo` doesn't really avoid unnecessary re-renders in our components. By default, the child components will always re-render if the parent component has triggered a render ([1](https://stackoverflow.com/a/40820657)). But, this can be override with shouldComponentUpdate for class-based component or with `React.memo(SomeComponent)` for functional component. `React.memo` prevents unnecessary re-renders if there's no change in the props (and no state update in the component itself), and we can use useMemo/useCallback to avoid creating new object when passing props to component each time. I attempted to use React.memo on DropdownInput for SearchBar (had to wrap a lot of things in useCallback), but there's a lot of props and state changes from SearchBar interactions that almost certainly would require a re-render of the subcomponents. Clicking in/out of searchbar, typing/submitting/clearing inputs in some way generally trigger some setState functions due to new results and/or make updates to the different contexts that would affect the Dropdown components. Additionally, some advise that components like Dropdown with [child prop shouldn't use React.memo ](facebook/react#14463 (comment) the children prop almost always changes. I believe there may **not** be a lot of benefits for doing useCallback throughout SearchBar to avoid re-renders in its subcomponents. It kind of make the codebase more complicated with the overhead and less readable, unless there's an actual performance bottleneck to address. So I'm a bit hesitant to add more useMemo/useCallback in our hooks and components if we don't need to. J=SLAP-1965 TEST=manual log number of renders in SearchBar before and after useRecentSearch changes. See that SearchBar have less re-renders on initial load.
…ches (#110) SearchBar requires multiple re-renders due to useEffect call in useRecentSearches to setup RecentSearches instance. The changes in this pr ensures a RecentSearches is set on the first render and only re-render if there is an update to `recentSearchesLimit`. Findings when attempt to memoize hooks and testing in SearchBar: Just using `useCallback` and `useMemo` doesn't really avoid unnecessary re-renders in our components. By default, the child components will always re-render if the parent component has triggered a render ([1](https://stackoverflow.com/a/40820657)). But, this can be override with shouldComponentUpdate for class-based component or with `React.memo(SomeComponent)` for functional component. `React.memo` prevents unnecessary re-renders if there's no change in the props (and no state update in the component itself), and we can use useMemo/useCallback to avoid creating new object when passing props to component each time. I attempted to use React.memo on DropdownInput for SearchBar (had to wrap a lot of things in useCallback), but there's a lot of props and state changes from SearchBar interactions that almost certainly would require a re-render of the subcomponents. Clicking in/out of searchbar, typing/submitting/clearing inputs in some way generally trigger some setState functions due to new results and/or make updates to the different contexts that would affect the Dropdown components. Additionally, some advise that components like Dropdown with [child prop shouldn't use React.memo ](facebook/react#14463 (comment) the children prop almost always changes. I believe there may **not** be a lot of benefits for doing useCallback throughout SearchBar to avoid re-renders in its subcomponents. It kind of make the codebase more complicated with the overhead and less readable, unless there's an actual performance bottleneck to address. So I'm a bit hesitant to add more useMemo/useCallback in our hooks and components if we don't need to. J=SLAP-1965 TEST=manual log number of renders in SearchBar before and after useRecentSearch changes. See that SearchBar have less re-renders on initial load.
This answered in React docs:
The biggest reason IMO React.memo is not enabled by default is that it can break rendering when props are mutable. However, it is best practice to not use mutable props in the first place. React.memo is ineffective if the props change each render, e.g.
That said, the cost is essentially nothing and it is up the caller to change passed props. IMO the callee should always use React.memo, and if the caller wants to take advantage of that, it can. |
I've removed the previous comment as it violates our code of conduct. As this thread has seen extensive on-topic discussion and is now becoming outdated, I'm going to lock it. |
I've been playing around with React 16.6.0 recently and I love the idea of React Memo, but I've been unable to find anything regarding scenarios best suited to implement it. The React docs (https://reactjs.org/docs/react-api.html#reactmemo) don't seem to suggest any implications from just throwing it on all of your functional components. Because it does a shallow comparison to figure out if it needs to re-render, is there ever going to be a situation that negatively impacts performance?
And second question: as long as everything remains pure, is there ever a situation to not wrap a functional component with React Memo?
Thank you.
The text was updated successfully, but these errors were encountered: