-
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 TabPanel
to pass exhaustive-deps
#44935
Conversation
@@ -104,7 +104,7 @@ export function TabPanel( { | |||
( tabs.length > 0 ? tabs[ 0 ].name : undefined ) | |||
); | |||
} | |||
}, [ tabs ] ); | |||
}, [ tabs, selected, initialTabName ] ); |
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 find()
on L100 is already done outside of the useEffect on L96:
const newSelectedTab = find( tabs, { name: selected } );
Could we perhaps reuse that selectedTab
variable instead of rerunning the find()
?
}, [ tabs, selected, initialTabName ] ); | |
}, [ tabs, selectedTab, initialTabName ] ); |
Like you say, it's not an expensive operation, but more hygienic and readable nonetheless 😄
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.
Good point - though I think we might want to memoize selectedTab
before introducing it as a dependency on the useEffect
.
The current dep selected
is a string, so it won't cause the effect to fire if the value doesn't change. selectedTab
is an object, so we'd end up firing the effect on each re-render. Updated in 465d9e2 what do you think?
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 ok. Maybe we could pass selectedTab?.name
instead of selectedTab
to the useEffect's dep array then, so we don't need to memoize. Would that work?
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, I think it will! Updated and rebased!
465d9e2
to
d0a8bf4
Compare
if ( ! newSelectedTab && tabs.length > 0 ) { | ||
handleTabSelection( initialTabName || tabs[ 0 ].name ); |
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.
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.
Yikes, I see what you mean. Thank you. Looking back at the commits, my previous change to memoize the value borked things up, and I didn't notice when we went to ?.name
so things are stayed broken. I've pushed a fix, restoring the missing lines/checks that should address the problem.
Your new tests do, indeed, help highlight this kind of issue, and they're passing for me locally now... but I'll wait for #45211 to merge before finalizing this one.
d0a8bf4
to
de66efe
Compare
This PR will need a rebase once #45265 is merged to include fixes to the PHP unit tests |
Co-authored-by: Lena Morita <lena@jaguchi.com>
b67db69
to
cb108f4
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.
Looks good! 🚀
What?
Updates the
TabPanel
component to satisfy theexhaustive-deps
eslint ruleWhy?
Part of the effort in #41166 to apply
exhuastive-deps
to the Components packageHow?
Adds two missing dependencies (
selected
andinitialTabName
) to the component'suseEffect
dep array.Adding
initialTabName
doesn't appear to cause any noticeable changes. Addingselected
, on the other hand, does mean this effect now fires on every render, though it doesn't appear to cause any additional re-renders.Previously, the effect only fired when the
tabs
props changed, and it was used to unsure the currently selected tab still existed. If not, it selects a fallback tab instead. With this change, the effect will also fire when a tab is selected and check that the selected tab exist (and it should, the user just clicked on it).This isn't an expensive check, so I don't think we need to worry about it. If we want to prevent the effect from firing more than it used to, we could use the Latest Ref pattern to track the currently selected tab and use that ref's value in the effect. That would eliminate the dependency on
selected
and restore the effect's behavior to what it was before, but I don't honestly think it's worth the readability cost.Testing Instructions
npx eslint --rule 'react-hooks/exhaustive-deps: warn' packages/components/src/tab-panel