-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Components: refactor TabPanel to pass exhaustive-deps
#44935
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
Conversation
| ); | ||
| } | ||
| }, [ 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 <[email protected]>
b67db69 to
cb108f4
Compare
mirka
left a 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.
Looks good! 🚀
What?
Updates the
TabPanelcomponent to satisfy theexhaustive-depseslint ruleWhy?
Part of the effort in #41166 to apply
exhuastive-depsto the Components packageHow?
Adds two missing dependencies (
selectedandinitialTabName) to the component'suseEffectdep array.Adding
initialTabNamedoesn'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
tabsprops 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
selectedand 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