-
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
Block Editor: Add client ID trees selectors #29902
Conversation
Size Change: +51 B (0%) Total Size: 1.4 MB
ℹ️ View Unchanged
|
d7df7b7
to
4a58e20
Compare
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.
@Copons the overall idea makes sense to me to slim down the memo'd selector to just clientIds. If __unstableGetBlockTree
is in use elsewhere it might be worth a similar cleanup in a follow up, as that cached work is highly likely to be thrown out with any block change.
Feel free to summon me back with a ping, when unit tests are ready.
Once y'all have a good baseline, it might be a good chance to add a perf E2E test for the site editor as a follow up. See example in post-editor. Really small changes can cause perf regressions.
typing.mp4
Manual testing with typing on this branch:
packages/block-editor/src/components/block-navigation/block-slot.js
Outdated
Show resolved
Hide resolved
|
||
const _selectedBlockClientId = getSelectedBlockClientId(); | ||
const _rootBlocks = __unstableGetClientIdsTree(); | ||
const _rootBlock = _selectedBlockClientId |
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.
General question, why the _
prefix?
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.
It's because those names are already declared in the upper scope.
The _
is just simpler than figure out some naming switcheroo that might compromise the readability.
(Also, I've seen it used plenty of times in Gutenberg, sometimes to mark a constant as "private", but often in this exact same context of select hooks.)
If things are still pretty expensive to update in the persistent list view, another idea might be to skip re-renders while the user is typing. There's core/block-editor state available for that via |
We should wrap this component with "AsyncProvider" to avoid rerendering this synchronously, it should improve the performance instantaneously. The other thing we could do later is instead of having a unique selector to retrieve the tree at the root component, have a selector to retrieve "children" blocks on each level, this means adding/removing blocks will only update the parent of that block and not the whole tree. (need to verify that it's more performant) |
@gwwar The only other use is Following the stack, it seems that in that case the blocks attributes are eventually used. @Addison-Stavlo do you have more insights on the function? Like, could it survive with just
Noice, I didn't think of the perf tests, will try to add them too along with unit!
@youknowriad TIL! (or at the very least: TIR, Today I Remembered 😄 ) gutenberg/packages/edit-site/src/components/secondary-sidebar/list-view-sidebar.js Lines 74 to 80 in e445c98
The performance gain is obvious, although this new slimmer selector should make things even quicker. |
4a58e20
to
d826cf9
Compare
packages/edit-site/src/components/secondary-sidebar/list-view-sidebar.js
Outdated
Show resolved
Hide resolved
@gwwar I've added the unit tests, but I'm having some troubles with the performance ones. I'd rather improve the Site Editor perf tests separately, to get them in relative parity with the Post Editor ones, before adding something related to the Persistent List View. 🤔 |
); | ||
const { selectBlock } = useDispatch( blockEditorStore ); | ||
|
||
function selectEditorBlock( clientId ) { |
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.
Any reason to use function
vs arrow function
?
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.
Not really, no. I don't think there's any practical difference in this case.
This is awesome. I'd be very interest to see how much this and the AsyncProvider improves the drag and drop performance in list view, that was always a little choppy with lots of blocks. |
This is a huge improvement! 🚀 Before ~70% of the frames are dropped Screen.Recording.2021-03-22.at.11.22.19.movAfter ~30% of the frames are dropped Screen.Recording.2021-03-22.at.11.23.04.mov |
Well @david-szabo97 @talldan if you like this so much, feel free to approve it! |
Description
As mentioned in #29636 (review), keeping the Persistent List View open slows down the editor to a crawl, especially noticeable when typing.
The cause is that the
BlockNavigation
uses the__unstableGetBlockTree
selector, which depends onstate.blocks.attributes
, which can change quite often, especially while typing, causing a ton of wasted re-renders of the whole list.This is not noticeable with the non-persistent List View, given that you can't edit your content with the list open.
Turns out that
BlockNavigation
doesn't really need to know all about blocks, but it can easily live with just theirclientId
s, as long as they are nested like the actual block tree.In this PR I've created a new
__unstableGetClientIdsTree
which is fundamentally similar to the full-fledged__unstableGetBlockTree
, but only usesclientId
s.The list doesn't re-render anymore when a block changes.
Although, the list does re-render when a block is added, removed, or moved around. The result is that there's still a noticeable delay between the click and the action outcome.
Notes
To avoid having to change the internal logic of
BlockNavigation
(and to keep this PR slim), the tree is pre-formatted with the expected properties:[ { clientId, innerBlocks: [ { ... }, ... ] }, { ... }, ... ]
I'm happy with rewriting all the things, but first I'd like to be sure this is the right way to go.
Same thing about the unit tests: I'll add them if we are cool with this approach.
I've also avoided to delete the
__unstableGetBlockTree
selector, as it's used elsewhere.How has this been tested?
Also double-check all the uses of the List View for regressions:
Types of changes
Bug fix (non-breaking change which fixes an issue)
Checklist: