Add eslint-plugin-react-you-might-not-need-an-effect#8000
Conversation
Enable the plugin's recommended preset to catch unnecessary React effects. Existing violations are suppressed inline with eslint-disable-next-line comments so they can be refactored over time.
|
|
There was a problem hiding this comment.
Pull request overview
This pull request introduces the eslint-plugin-react-you-might-not-need-an-effect ESLint plugin and enables its recommended preset in the repo’s flat ESLint config, then suppresses all pre-existing violations inline so new code is linted immediately without introducing warnings.
Changes:
- Add
eslint-plugin-react-you-might-not-need-an-effect@1.0.1to dev dependencies and wire itsrecommendedconfig intoeslint.config.mjs. - Add/merge
// eslint-disable-next-line react-you-might-not-need-an-effect/...directives across existinguseEffectsites to suppress legacy violations. - Update
package-lock.jsonto reflect the new dependency (and additional workspace/version changes that appear unrelated to the described scope).
Show a summary per file
| File | Description |
|---|---|
| eslint.config.mjs | Imports the plugin and enables its configs.recommended preset in the flat config array. |
| package.json | Adds the new ESLint plugin to root devDependencies. |
| package-lock.json | Adds the new plugin to the lockfile; also includes workspace/version bumps that don’t match the PR’s stated scope. |
| packages/react/src/utils/StressTest.tsx | Adds inline disables for plugin findings in an existing effect. |
| packages/react/src/utils/descendant-registry.tsx | Adds inline disable for no-pass-data-to-parent on an existing state update. |
| packages/react/src/TreeView/TreeView.tsx | Merges plugin rule disables into existing eslint-disable-next-line directives and adds a few new ones. |
| packages/react/src/TooltipV2/Tooltip.tsx | Adds inline disable for no-event-handler in an existing effect. |
| packages/react/src/ToggleSwitch/ToggleSwitch.tsx | Merges/introduces inline disables around existing effect-driven state updates. |
| packages/react/src/Textarea/Textarea.tsx | Adds inline disables for plugin findings in existing character counter effects. |
| packages/react/src/Spinner/Spinner.tsx | Adds inline disable for an existing delay effect. |
| packages/react/src/SelectPanel/SelectPanel.tsx | Adds multiple inline disables across existing effects (loading, focus, announcements, sorting). |
| packages/react/src/SelectPanel/SelectPanel.features.stories.tsx | Adds inline disables in story effects to suppress legacy findings. |
| packages/react/src/SelectPanel/SelectPanel.examples.stories.tsx | Adds inline disables in example story effects to suppress legacy findings. |
| packages/react/src/SelectPanel/SelectPanel.dev.stories.tsx | Adds inline disables in dev story effect to suppress legacy findings. |
| packages/react/src/Portal/Portal.features.stories.tsx | Adds inline disables for no-initialize-state in existing mount effects. |
| packages/react/src/Overlay/Overlay.features.stories.tsx | Adds inline disable for an existing focus-on-editing effect. |
| packages/react/src/LabelGroup/LabelGroup.tsx | Adds inline disables in existing truncation/overflow-related effects. |
| packages/react/src/internal/components/ValidationAnimationContainer.tsx | Merges plugin disables into an existing state-in-effect suppression. |
| packages/react/src/hooks/useMnemonics.ts | Adds inline disable in an existing effect that mutates DOM attributes. |
| packages/react/src/hooks/useMenuInitialFocus.ts | Adds inline disable for an effect that moves focus on open. |
| packages/react/src/hooks/useMedia.ts | Merges plugin disable with existing set-state-in-effect suppression. |
| packages/react/src/hooks/useFocusZone.ts | Adds inline disable within existing effect guard conditions. |
| packages/react/src/hooks/useDialog.ts | Adds inline disables around existing “open” effects (listeners, focus). |
| packages/react/src/hooks/useDetails.tsx | Adds inline disable for an existing click-outside effect. |
| packages/react/src/hooks/useControllableState.ts | Adds inline disables in an effect that emits controlled/uncontrolled warnings. |
| packages/react/src/FormControl/FormControl.features.stories.tsx | Adds inline disables around story-only validation state effects. |
| packages/react/src/FilteredActionList/useAnnouncements.tsx | Adds inline disable for an existing announcement condition inside an effect. |
| packages/react/src/FilteredActionList/FilteredActionList.tsx | Adds inline disables for effects that pass refs upward / manage roving tabindex state. |
| packages/react/src/experimental/SelectPanel2/SelectPanel.tsx | Adds inline disable for an existing initial focus effect. |
| packages/react/src/experimental/SelectPanel2/SelectPanel.examples.stories.tsx | Merges plugin disable into an existing state-in-effect suppression. |
| packages/react/src/Dialog/Dialog.tsx | Merges plugin disable into existing state-in-effect suppression. |
| packages/react/src/Dialog/Dialog.features.stories.tsx | Adds inline disable for an existing step-focus effect. |
| packages/react/src/DataTable/storybook/data.ts | Adds inline disables around an existing query effect’s state resets. |
| packages/react/src/Breadcrumbs/Breadcrumbs.tsx | Adds inline disables around an existing overflow-calculation effect. |
| packages/react/src/AvatarStack/AvatarStack.tsx | Adds inline disable for an existing “initialize on mount” effect call. |
| packages/react/src/Autocomplete/AutocompleteMenu.tsx | Adds inline disables for effects that sync derived state / notify parent / compute suggestion text. |
| packages/react/src/Autocomplete/AutocompleteInput.tsx | Adds inline disable within existing logic that highlights remaining text. |
| packages/react/src/Autocomplete/Autocomplete.features.stories.tsx | Adds inline disable for a story mount effect state update. |
| packages/react/src/AnchoredOverlay/AnchoredOverlay.tsx | Adds inline disable for an effect that clears overlay ref on close. |
| packages/react/src/ActionList/Description.tsx | Adds inline disables for effect-driven DOM text extraction to compute tooltip/title. |
Copilot's findings
- Files reviewed: 39/40 changed files
- Comments generated: 0
Resolve conflicts from Add eslint-plugin-react-you-might-not-need-an-effect (#8000): - Keep useSyncExternalStore implementation in useMedia.ts (our refactor) - Keep render-time derivation in ValidationAnimationContainer.tsx (our refactor) - Keep render-time derivation in SelectPanel.tsx intermediateSelected (our refactor) - Keep render-time derivation in ToggleSwitch.tsx; add no-event-handler suppression - Merge descriptive comments with new react-you-might-not-need-an-effect suppressions in Dialog.tsx, AutocompleteMenu.tsx, SelectPanel.tsx, and TreeView.tsx Co-authored-by: mattcosta7 <8616962+mattcosta7@users.noreply.github.com>
Closes #
What
Adds
eslint-plugin-react-you-might-not-need-an-effectand wires it into our flat ESLint config via itsrecommendedpreset. The plugin flagsuseEffectusage that the React docs describe under "You Might Not Need an Effect" — storing derived state, running event-handler logic, chaining state updates, resetting/adjusting state on prop changes, passing data up to parents, subscribing to external stores, and initializing state in an effect.Because the codebase already contains effects that trip these rules, the pre-existing violations are suppressed inline with
// eslint-disable-next-linecomments (107 sites across 37 files) rather than disabling the rules globally. New code is linted immediately; each legacy case is individually marked so it can be revisited and removed over time.Why
How
eslint.config.mjs: import the plugin and addreactYouMightNotNeedAnEffect.configs.recommended(enables all 9 rules as warnings across JS/TS files).// eslint-disable-next-linecomments — the repo'seslint-comments/no-userule bans whole-file/* eslint-disable */blocks, and per-line directives are the convention already used throughout the repo.react-hooks/set-state-in-effect), the new rule id was merged into the existing comment rather than added on a separate line, to avoid "unused directive" errors (lint runs with--max-warnings=0).Changelog
New
eslint-plugin-react-you-might-not-need-an-effectand its recommended ESLint configuration.Changed
Removed
Rollout strategy
@primer/reactpackage, so no changeset is required (theskip changesetlabel is applied).Testing & Reviewing
npm run lintpasses with--max-warnings=0— zero remaining plugin violations and zero unused disable directives.eslint.config.mjs; everything else is// eslint-disable-next-lineannotations.Merge checklist