-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
New useBlockElementRef hook for storing block element into a ref #63799
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: -20 B (0%) Total Size: 1.76 MB
ℹ️ View Unchanged
|
*/ | ||
function useBlockRef( clientId ) { | ||
export function useBlockElementRef( clientId, ref ) { |
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.
Why can't we set the ref
that is provided here directly on refsMap
to be used by the 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.
You mean, the refs would be stored directly in the refsMap
instead of the element? And the refsMap
job would be to "forward" the ref callback calls to the registered consumers?
I think in that case it would be hard to register a new ref at a time when the block is already mounted. When calling:
useBlockElementRef( clientId, ref );
The ref
wouldn't be set until the block element is changed or recreated.
ref.current = el; | ||
} | ||
}, | ||
[ ref ] |
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.
Could we not avoid the useCallback
here by moving the function within the useLayoutEffect
that follows?
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.
Or setRef( ref, element )
could even be outside the hook
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.
Haha, there's actually also assignRef
in use-merge-refs
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 that we can use it here, it's a different package
gutenberg/packages/compose/src/hooks/use-merge-refs/index.js
Lines 18 to 27 in 47bde1a
function assignRef( ref, value ) { | |
if ( typeof ref === 'function' ) { | |
ref( value ); | |
} else if ( ref && ref.hasOwnProperty( 'current' ) ) { | |
/* eslint-disable jsdoc/no-undefined-types */ | |
/** @type {import('react').MutableRefObject<T>} */ ( ref ).current = | |
value; | |
/* eslint-enable jsdoc/no-undefined-types */ | |
} | |
} |
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.
Here we need to ensure that when the ref
parameter in useBlockElementRef( clientId, ref )
changes, the new version is called immediately. That's what React also does. When a different ref
is passed to <div ref={ ref } />
, then even though the div
element is still the same, it will call the old ref with null
and the new ref with the 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.
The layout effect will still be called when adding ref
as a dependency?
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 that we can use it here, it's a different package
Interesting, I didn't know about that. The ref.hasOwnProperty( 'current' )
check is nice, but not even React bothers to do it. It checks ref !== null
, typeof ref === 'function'
, and then if ref.current
assignment leads to a crash, it will crash, it's you fault.
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.
The layout effect will still be called when adding ref as a dependency?
Now I get it, of course you're right, fixing in 26e153a. It's a nice simplification.
packages/block-editor/src/components/block-list/use-block-props/use-block-refs.js
Outdated
Show resolved
Hide resolved
26e153a
to
9f4ee9b
Compare
Hey @jsnajdr 👋 Would you be able to help write a dev note for this for the 6.7 release? We are planning to have this as part of a larger Miscellaneous Editor Updates note. We are hoping to get all drafts in by October 13th to leave some time for reviews before the RC1. All Dev Notes get tracked in #65784 so feel free to leave a note there or ping me directly :) Please let us know if you can assist with that. Thanks in advance :) |
Hi @fabiankaegy 👋 I believe that dev note is not needed here, because the PR modifies only internal APIs used inside the |
Ahh my bad. Will remove it from the list then :) |
Implements idea from #63565 (comment), replacing the
useBlockRef
hook with a newuseBlockElementRef
one. The difference is that the hook doesn't return a ref, but accepts one as a parameter. That's similar to how a JSX markup like<div ref={ divRef } />
also accepts a ref as a parameter.This hook can be used to easily implement the
useBlockElement
hook.This PR also removes the
__unstable
prefixes from the exports because they are all internal API anyway, they are not exported from theblock-editor
package.For correct types, I also had to add exports of the
RefCallback
andRef
React types toelement
.