Block Editor: Add a new hook for getting a stable block context object#47028
Conversation
|
Size Change: +208 B (0%) Total Size: 1.33 MB
ℹ️ View Unchanged
|
|
Flaky tests detected in 1904d75. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/3900672955
|
1b591cf to
2a4af31
Compare
|
|
||
| // Wrap context provider if (and only if) block has context to provide. | ||
| const blockType = getBlockType( block.name ); | ||
| if ( blockType && blockType.providesContext ) { |
There was a problem hiding this comment.
This original condition was always true, so there's no harm in wrapping the block in a context provider similar to the web version. See #46729.
| const context = getBlockContext( block.attributes, blockType ); | ||
|
|
||
| blockList = ( | ||
| <LayoutProvider value={ layout }> |
There was a problem hiding this comment.
Seems to me you fixed a bug here: previously, if the component didn't provide a context, but did provide a layout, the LayoutProvider wasn't rendered and the layout wasn't applied.
I see quite a few blocks, very common ones, that are like this, i.e., their block.json has supports.__experimentalLayout field, but doesn't have providesContext. Buttons, Column, Columns, Group, ...
There was a problem hiding this comment.
Sort of. This was only working because blockType && blockType.providesContext was always truthy.
There was a problem hiding this comment.
Oh yes, so it was only potential, not real bug 👍
jsnajdr
left a comment
There was a problem hiding this comment.
Perfect! Thank you for working on this 👍
| return undefined; | ||
| } | ||
|
|
||
| if ( Object.keys( blockType.providesContext ).length === 0 ) { |
There was a problem hiding this comment.
Any chance provideContext will not exist, causing Object.keys( undefined ) to crash?
There was a problem hiding this comment.
When providesContext doesn't exist in block.json, it will get defaulted to an empty object here.
There's only one edge case: if I specify providesContext: null in block.json, it will not get defaulted and Object.keys will really crash.
There was a problem hiding this comment.
Maybe it's worth adding a ?? {} or an additional non-nullish check just in case.
There was a problem hiding this comment.
I realized there's the providesContext: null case only after your comment.
There was a problem hiding this comment.
That sounds like intentionally breaking a block. What if someone sets a string instead of an object?
I think this is something that block register should handle.
There was a problem hiding this comment.
String is fine, it's an array-like object that has keys. Even number will be accepted. Only null or undefined will crash.
There was a problem hiding this comment.
I think this is something that block register should handle.
I don't disagree, after all, we probably have many places where we expect a string value in block.json, and do unguarded .includes or .startsWith calls. A malicious null will crash them, too.
There was a problem hiding this comment.
Agreed. That's why I approved the PR in the first place and considered this a minor thing. Leaving it to your judgement @Mamaduka.
There was a problem hiding this comment.
Thanks again for the great feedback. I will merge this as it is. But happy to add extra checks in the future. Maybe as a part of block registration.
geriux
left a comment
There was a problem hiding this comment.
All good from the mobile side 🚀
What?
See #46797
PR adds a new hook for getting a stable block context object.
Why?
Currently, every attribute update causes the BlockContextProvider value to change. Providers and consumers should only care when attributes provided as context are updated.
How?
PR replaces
getBlockContextwith the newuseBlockContexthook (props @jsnajdr #46797 (comment)) that relies onuseSelectinternal memoization to ensure context's stable reference.Testing Instructions
Testing this improvement requires profiling React renders. In my tests, I've used Gallery block with few images while typing in Gallery block's caption field. The caption isn't provided via context, so it shouldn't cause context updates.
Below is a screencast of before and after profiles.
Screencast
CleanShot.2023-01-12.at.13.22.55.mp4