-
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
Components: refactor SlotFill
to pass exhaustive-deps
#44403
Conversation
Size Change: -3 B (0%) Total Size: 1.27 MB
ℹ️ View Unchanged
|
7ae82de
to
0d7c7f6
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.
Given the complexity of this component, it would be great if @youknowriad could take a look and advise on the best way to fix the exhaustive deps linter warning 🙏
useLayoutEffect( () => { | ||
registry.registerSlot( name, ref, fillProps ); | ||
registerSlot( name, ref, fillPropsRef.current ); |
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.
If the original intention was to "only consider the initial value of fillProps
", then using a ref may cause that behaviour to change
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.
Can you explain that a bit more for me? My hope was that if we store the initial value in the ref, and then don't update that ref at all, then the initial value should be preserved, regardless of what happens to fillProps
itself later on. Am I not thinking about the ref behavior correctly?
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.
Excuses for not explaining myself correctly before. What you say is true, but your code changes may introduce a difference in behavior.
Imagine this scenario:
- component renders for the first time,
useLayoutEffect
runs and callsregisterSlot
with the initial value offillProps
- later, the component re-renders and one of the dependencies of this
useLayoutEffect
has changed — this will cause theuseLayoutEffect
to run again and callregisterSlot
again.- with the code written as it is on
trunk
,registerSlot
will use the latest value offillProps
, which may be different from the initial value - with the changes from this PR,
registerSlot
will keep using the initial value offillProps
. This means that if in the meantime the value offillProps
changed, it would be ignored.
- with the code written as it is on
I'm not exactly sure which one was the intended behaviour here, but I wanted to flag this potential change. @youknowriad , could you advise on which of these two scenarios sounds the most correct to you, please? Thank you!
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.
Indeed that's problematic behavior, I missed it. The fillProps used should always be the last ones, not the initial ones but there's no need to re-register if they change, because there's a hook right after that update them when they change.
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.
Thank you, Riad!
@chad1008 , probably the best thing to do here is also to revert the changes, and simply add an eslint-disable
comment.
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.
Ah, thank you for clarifying @ciampo, and for the second look @youknowriad!
I think it was the and we are only considering the initial value of fillProps
part of the existing comment that through me off, but looking more closely after the above explanation I see exactly what you mean. I'm going to remove that 'initial value' bit from the comment, add an ignore, and link back here.
For any future refactors that are led here by that code comment: unless a more comprehensive refactor is needed, the Latest Ref pattern might be of use here. We could store fillProps
in a ref for use in the useLayoutEffect
, and keep it up to date as it changes... but the ref wouldn't be a dependency so we wouldn't need to add it to the array. This way when the effect does fire, the ref will contain the latest value, but changes to that value won't trigger anything themselves.
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 changes here look good to me.
cbf0f70
to
e378d2e
Compare
… fully refactored
c4aed99
to
fbb48f2
Compare
@@ -23,6 +23,7 @@ | |||
- `withFocusReturn`: Refactor tests to `@testing-library/react` ([#45012](https://github.com/WordPress/gutenberg/pull/45012)). | |||
- `ToolsPanel`: updated to satisfy `react/exhaustive-deps` eslint rule ([#45028](https://github.com/WordPress/gutenberg/pull/45028)) | |||
- `Tooltip`: updated to ignore `react/exhaustive-deps` eslint rule ([#45043](https://github.com/WordPress/gutenberg/pull/45043)) | |||
- `SlotFill`: updated to satisfy `react/exhaustive-deps` eslint rule ([#44403](https://github.com/WordPress/gutenberg/pull/44403)) |
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.
This CHANGELOG entry got added under the wrong version, maybe we can move it as part of another exhaustive-deps
related PR ?
What?
Updates the
SlotFill
component to satisfy theexhaustive-deps
eslint ruleWhy?
Part of the effort in #41166 to apply
exhuastive-deps
to the Components packageHow?
.../slot-fill/bubbles-virtually/fill.js:
Due to issues with how
this
applies to reading methods from an object, the lint rule wants to see the fullslot
object as a dependency and not the methods themselves. To resolve this, we can destructure the methods beforehand, so our dependencies reflect the methods themselves..../slot-fill/bubbles-virtually/slot.js:
registerSlot
andunregisterSlot
have been destructured for the same reasons as the dependencies above.It was noted in the comments that
fillProps
were intentionally left out of the array to avoid un-and-reregistering the fill on every single prop change. We really only want the initial value. That makes sense, but causes our favorite lint rule a lot of anxiety, so I've placed the initialfillProps
value into a ref that doesn't get updated, and used that in the layout effect..../src/slot-fill/fill.js & .../slot-fill/use-slot.js
The warnings here have been treated with
eslint ignore
comments for now, as they may require a more in-depth refactor. theuseLayoutEffect
s in slot-fill/fill.js in particular look like they were written to fire at very specific points.cc'ing @youknowriad in case you're able to assist or offer any advice on updating this component to pass the
exhaustive-deps
es-lint
rule.Testing Instructions
npx eslint --rule 'react-hooks/exhaustive-deps: warn' packages/components/src/slot-fill