-
Notifications
You must be signed in to change notification settings - Fork 4.7k
SlotFill: fix a bug with storing stale fillProps #67000
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,22 +34,34 @@ function createSlotRegistry(): SlotFillBubblesVirtuallyContext { | |
|
|
||
| const unregisterSlot: SlotFillBubblesVirtuallyContext[ 'unregisterSlot' ] = | ||
| ( name, ref ) => { | ||
| const slot = slots.get( name ); | ||
| if ( ! slot ) { | ||
| return; | ||
| } | ||
|
|
||
| // Make sure we're not unregistering a slot registered by another element | ||
| // See https://github.com/WordPress/gutenberg/pull/19242#issuecomment-590295412 | ||
| if ( slots.get( name )?.ref === ref ) { | ||
| slots.delete( name ); | ||
| if ( slot.ref !== ref ) { | ||
| return; | ||
| } | ||
|
|
||
| slots.delete( name ); | ||
| }; | ||
|
|
||
| const updateSlot: SlotFillBubblesVirtuallyContext[ 'updateSlot' ] = ( | ||
| name, | ||
| ref, | ||
| fillProps | ||
| ) => { | ||
| const slot = slots.get( name ); | ||
| if ( ! slot ) { | ||
| return; | ||
| } | ||
|
|
||
| if ( slot.ref !== ref ) { | ||
| return; | ||
| } | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is second critical line of the patch, adding a check if |
||
|
|
||
| if ( isShallowEqual( slot.fillProps, fillProps ) ) { | ||
| return; | ||
| } | ||
|
|
@@ -69,20 +81,18 @@ function createSlotRegistry(): SlotFillBubblesVirtuallyContext { | |
| fills.set( name, [ ...( fills.get( name ) || [] ), ref ] ); | ||
| }; | ||
|
|
||
| const unregisterFill: SlotFillBubblesVirtuallyContext[ 'registerFill' ] = ( | ||
| name, | ||
| ref | ||
| ) => { | ||
| const fillsForName = fills.get( name ); | ||
| if ( ! fillsForName ) { | ||
| return; | ||
| } | ||
| const unregisterFill: SlotFillBubblesVirtuallyContext[ 'unregisterFill' ] = | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here I'm fixing a typo in the type: changing |
||
| ( name, ref ) => { | ||
| const fillsForName = fills.get( name ); | ||
| if ( ! fillsForName ) { | ||
| return; | ||
| } | ||
|
|
||
| fills.set( | ||
| name, | ||
| fillsForName.filter( ( fillRef ) => fillRef !== ref ) | ||
| ); | ||
| }; | ||
| fills.set( | ||
| name, | ||
| fillsForName.filter( ( fillRef ) => fillRef !== ref ) | ||
| ); | ||
| }; | ||
|
|
||
| return { | ||
| slots, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,29 +35,33 @@ function Slot( | |
| as, | ||
| // `children` is not allowed. However, if it is passed, | ||
| // it will be displayed as is, so remove `children`. | ||
| // @ts-ignore | ||
| children, | ||
| ...restProps | ||
| } = props; | ||
|
|
||
| const { registerSlot, unregisterSlot, ...registry } = | ||
| useContext( SlotFillContext ); | ||
|
|
||
| const ref = useRef< HTMLElement >( null ); | ||
|
|
||
| // We don't want to unregister and register the slot whenever | ||
| // `fillProps` change, which would cause the fill to be re-mounted. Instead, | ||
| // we can just update the slot (see hook below). | ||
| // For more context, see https://github.com/WordPress/gutenberg/pull/44403#discussion_r994415973 | ||
| const fillPropsRef = useRef( fillProps ); | ||
| useLayoutEffect( () => { | ||
| fillPropsRef.current = fillProps; | ||
| }, [ fillProps ] ); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In general this is an indication that something should have been defined using the new
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunately
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What I was thinking is that we could do something like
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, if we really wanted to use |
||
|
|
||
| useLayoutEffect( () => { | ||
| registerSlot( name, ref, fillProps ); | ||
| registerSlot( name, ref, fillPropsRef.current ); | ||
| return () => { | ||
| unregisterSlot( name, ref ); | ||
| }; | ||
| // We don't want to unregister and register the slot whenever | ||
| // `fillProps` change, which would cause the fill to be re-mounted. Instead, | ||
| // we can just update the slot (see hook below). | ||
| // For more context, see https://github.com/WordPress/gutenberg/pull/44403#discussion_r994415973 | ||
| }, [ registerSlot, unregisterSlot, name ] ); | ||
| // fillProps may be an update that interacts with the layout, so we | ||
| // useLayoutEffect. | ||
|
|
||
| useLayoutEffect( () => { | ||
| registry.updateSlot( name, fillProps ); | ||
| registry.updateSlot( name, ref, fillPropsRef.current ); | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a critical line in the patch, adding a |
||
| } ); | ||
|
|
||
| return ( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,8 +21,10 @@ export default function useSlot( name: SlotKey ) { | |
|
|
||
| const api = useMemo( | ||
| () => ( { | ||
| updateSlot: ( fillProps: FillProps ) => | ||
| registry.updateSlot( name, fillProps ), | ||
| updateSlot: ( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where is this one used. or is it not used at all? I see the function arguments modified but I don't see where the calling of the function is updated.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The The bug being fixed is triggered when, for any reason, the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But this one updateSlot that is returned from useSlot, is not used right?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh yes, this is a good observation. The |
||
| ref: SlotFillBubblesVirtuallySlotRef, | ||
| fillProps: FillProps | ||
| ) => registry.updateSlot( name, ref, fillProps ), | ||
| unregisterSlot: ( ref: SlotFillBubblesVirtuallySlotRef ) => | ||
| registry.unregisterSlot( name, ref ), | ||
| registerFill: ( ref: SlotFillBubblesVirtuallyFillRef ) => | ||
|
|
||
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 I'm just tidying up the code, no behavior change.
unregisterSlotandupdateSlotnow do the samerefcode and the code looks also the same.