-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Optimize BlockStyles by using hooks and React.memo (instead of HOCs) #21973
Conversation
@@ -7,6 +7,8 @@ import classnames from 'classnames'; | |||
/** | |||
* WordPress dependencies | |||
*/ | |||
import isShallowEqual from '@wordpress/is-shallow-equal'; | |||
import { memo } from '@wordpress/element'; |
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.
noting that we also have a "pure" hoc which is the same thing (before the existence of memo), not sure if we should deprecate it or not.
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.
I also find both these hocs to be less and less useful with hooks
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.
I have no strong preference here - I'm fine with just memo
, but if you think it would be cleaner with pure
I'll update it.
Size Change: +49 B (0%) Total Size: 816 kB
ℹ️ View Unchanged
|
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.
I have trouble understanding why we need "memo" here since for me withSelect/useSelect should already not rerender if you don't include the "block" prop (with the updated code)?
Some random questions :)
|
I believe gutenberg/packages/data/src/components/with-select/index.js Lines 50 to 60 in 4857ad5
Nothing overly scientific :-) During my work on #21948 I noticed typing in block inspector is super slow. 60 FPS video would be much better medium to show the problem, but let's try with GIF: Without the PR the slowness is impossible to ignore - letters are not showing immediately in response to my input, and they often appear in chunks of 2-6.
I did not! Hmm.. useSelect would receive new block after every key stroke too so it sounds like this approach would still involve memo/pure at some point? |
🤔 withSelect uses useSelect which IIRC doesn't rerender if the callback returns the same props (at least it's supposed to not rerender) |
I tried removing the |
@youknowriad I replaced HOC with hooks ( |
Thanks for the updates @adamziel Do you happen to know why the wrapping in "memo" is needed here? I mean the issue could probably be on a parent component rerendering where it shouldn't? |
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.
Code looks good to me, Ideally we get rid of the "memo" usage too if possible.
@youknowriad that's exactly the case. I would consider it a related, but separate problem. I am profiling right now and if the fix is simple enough I may be able to propose another PR today. I still think we should use |
Or am I missing something? Is there any downside to using memo() as long as we're careful not to use it everywhere? |
@adamziel With the number of components rendered in the tree, memoization has costs, if it's on a component that is rendered very high in the tree, it has almost no cost but the more we go down, the more costful it can be because the same component can be rendered in a loop or something. I think also memoization can hide some problems that need solving so I personally prefer avoiding it if possible. |
@youknowriad In principle I agree. In this very specific instance, I still think memo() is justified. This component is indeed pretty deep in the tree, but it's an expensive one - it creates a pretty large, dynamic/arbitrary tree of it's own. It seems unlikely to become a basic component that's instantiated in hundreds/thousands times within a single tree. As for hiding other problems, I fully agree. One such problem I've seen is that these style preview are full of RichText instances and other edit-specific components. It's not a terrible problem, but ideally they would only contain bare minimum amount of components necessary to display the preview. Also, I think I found the reason behind the parent component being re-rendered. Let's continue the discussion in #21990 |
Description
BlockStyles depend on the value of a
block
, which means they're re-rendered every time an attribute is updated. This is pretty slow, especially if it happens after every key stroke (see #21948). This PR leveragesReact.memo
anduseSelect
to avoid re-renders in cases where block example is available.Test plan
packages/block-library/src/navigation/index.js
and repeat previous steps. I think all core blocks come with an example so it seems to be the easiest way to test. In this scenario, confirm that the style preview is updated to reflect all the updates to block attributes - e.g. changing background color should be reflected in the preview right away.Types of changes
Bug fix (non-breaking change which fixes an issue)
Checklist: