-
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: optimise hasSelectedInnerBlock selector #60330
Conversation
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.
To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Size Change: +23 B (0%) Total Size: 1.72 MB
ℹ️ View Unchanged
|
return selectedBlockClientIds.some( ( id ) => | ||
// Pass true because we don't care about order and it's more | ||
// performant. | ||
getBlockParents( state, id, true ).includes( 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.
I wonder if we can stop this as a single block. (Maybe we can if the current block clientId is not selected)
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 sure what you mean, do you mean merging with the non deep code block?
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 mean if one single selected block is not within the clientId
, probably the others won't be and we could just check selectedBlockClientIds[ 0 ]
That said:
- This only works if the
clientId
is not within the selection itself. - It is based on an assumption that non-consecutive selection is not supported.
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.
Let's keep it future proof then :)
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.
Two ideas that could make it even faster:
- Looking at the logic in
getSelectedBlockClientIds
, all multi-selected blocks always have a common parent. I can select multiple children of one block, but I can't select the last item of one list and first item of a second list. Trying to do this in the editor will select the entire two lists. Therefore, we need to check just one of the selected block, the parents are always the same and all the.some
tests are identical. That's the Riad's idea basically. - Instead of calling
getBlockParents
, what if we proceeded one parent at a time, withgetBlockRootClientId
? Then we don't have to construct the parents array.
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.
Yes, but not sure if it's valuable after the lack of a real improvement in the metric. The most important is that we don't run anything if no block is selected, and if there is, it's a pretty small loop. For multi selection yes, I guess we could just check the first ID. Not sure if we'd want to keep it future proof for non consecutive selection.
It doesn't seem to impact the metrics though. |
Strange, I am seeing it in the performance recordings though 🤔 |
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.
Looks like a really good optimization 👍
Clever call to reverse it and start from the selected blocks instead of looping through all the child blocks.
I'm curious to see the codevitals results.
🚀
if ( ! selectedBlockClientIds.length ) { | ||
return false; | ||
} |
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.
That's a pretty neat optimization on its own - we only care about selected blocks, so no need to loop through all of them.
isBlockSelected( state, innerClientId ) || | ||
isBlockMultiSelected( state, innerClientId ) || | ||
( deep && hasSelectedInnerBlock( state, innerClientId, deep ) ) | ||
const selectedBlockClientIds = getSelectedBlockClientIds( state ); |
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.
That's a neat way to check for both single- and multi-selection 👍
( innerClientId ) => | ||
isBlockSelected( state, innerClientId ) || | ||
isBlockMultiSelected( state, innerClientId ) || | ||
( deep && hasSelectedInnerBlock( state, innerClientId, deep ) ) |
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.
Removing a recursion in favor of a loop usually results in a performance improvement 👍
return selectedBlockClientIds.some( ( id ) => | ||
// Pass true because we don't care about order and it's more | ||
// performant. | ||
getBlockParents( state, id, true ).includes( 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.
I wonder if we need a test with 3 levels of nested blocks, but from what I understand, if we have blocks X > Y > Z (Z nested in Y, Y nested in X), and Z is selected, hasSelectedInnerBlock
should return false
by design, right?
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.
Should return false
for what? If Z is selected it will return true
for both X and Y unless you remove the deep flag
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.
Got it 👍
Co-authored-by: ellatrix <ellatrix@git.wordpress.org> Co-authored-by: youknowriad <youknowriad@git.wordpress.org> Co-authored-by: tyxla <tyxla@git.wordpress.org>
What?
Optimises the selector by looking at the selection and checking if the parent (or any of the parents) match the clientId. Skips checks if no blocks are selected.
Why?
This selector is terribly unperformant. Just by opening 3 templates, it runs 2.5 million times.
How?
Testing Instructions
Testing Instructions for Keyboard
Screenshots or screencast