Skip to content

Migrate from eslint-plugin-react to @eslint-react/eslint-plugin for ESLint 10 - #3017

Closed
tanem wants to merge 2 commits into
masterfrom
migrate-eslint-react-plugin
Closed

Migrate from eslint-plugin-react to @eslint-react/eslint-plugin for ESLint 10#3017
tanem wants to merge 2 commits into
masterfrom
migrate-eslint-react-plugin

Conversation

@tanem

@tanem tanem commented May 22, 2026

Copy link
Copy Markdown
Owner

Summary

  • Replaces eslint-plugin-react@7.37.5 with @eslint-react/eslint-plugin@5.8.4 — the blocker for ESLint 10 adoption. The old plugin caps its peer at eslint ^9.7 and has a known runtime incompatibility with ESLint 10 (jsx-eslint/eslint-plugin-react#3977, #3970).
  • Bumps eslint 9.39.3 → 10.4.0, @eslint/js 9.39.3 → 10.0.1, and eslint-plugin-react-hooks 7.0.1 → 7.1.1 (adds ESLint 10 peer support).
  • Drops react/jsx-sort-props (no equivalent in @eslint-react).
  • Turns off @eslint-react/exhaustive-deps (covered by react-hooks/exhaustive-deps), @eslint-react/naming-convention-ref-name (library internals use descriptive ref names intentionally), and @eslint-react/use-state (intentional pattern in useGetSetState).
  • Fixes a no-useless-assignment lint error in src/useGetSetState.ts (++numnum + 1).
  • Updates examples/next-app-router/components/NavigationProgress.tsx with React 19 patterns: use() over useContext(), <Context> over <Context.Provider>.

Supersedes and closes #2988.

Test plan

  • npm run lint — clean (no errors or warnings)
  • npm run check:types — passes
  • npm test — full suite passes: format, types, lint, build, test:cjs, test:cjsprod, test:es, test:react (React 16.14 / 17.0 / 18.0 / 18.3 / 19.0), test:src (100% coverage), test:umd, test:umdprod

tanem added 2 commits May 23, 2026 06:37
…SLint 10

eslint-plugin-react@7.37.5 caps its peer at eslint ^9.7 and is
runtime-incompatible with ESLint 10 (upstream #3977/#3970 open), making
it the sole blocker for the ESLint 10 upgrade.

Switch to @eslint-react/eslint-plugin@5.8.4 — a modern, TypeScript-first
replacement that supports ESLint 10 today. Accept the loss of jsx-sort-props
(no equivalent in the new plugin). Also bump eslint-plugin-react-hooks to
7.1.1 which adds eslint ^10 peer support.

Violations surfaced by the new plugin:
- Turn off @eslint-react/exhaustive-deps (covered by react-hooks/exhaustive-deps)
- Turn off @eslint-react/naming-convention-ref-name (library internals use
  descriptive ref names intentionally)
- Turn off @eslint-react/use-state (intentional pattern in useGetSetState)
- Fix no-useless-assignment in useGetSetState (++num -> num + 1)
- Update next-app-router example: use() over useContext(), <Context> over
  <Context.Provider> (React 19 conventions)

Supersedes Renovate PR #2988.
Re-enable naming-convention-ref-name and use-state by fixing the code:
rename useRef bindings to end in Ref and replace the useState-based
force-update in useGetSetState with useReducer (the idiomatic pattern).

Replace the single @eslint-react/exhaustive-deps off with an explicit
dedup pair that keeps eslint-plugin-react-hooks as the hooks authority:
@eslint-react/exhaustive-deps and @eslint-react/rules-of-hooks are both
disabled because react-hooks/exhaustive-deps and react-hooks/rules-of-hooks
(the React team's canonical implementations) already cover those concerns.
@tanem

tanem commented Jul 29, 2026

Copy link
Copy Markdown
Owner Author

Superseded by #3018, now merged as 14fffc7.

That PR does the same migration but keeps it separate from the ESLint 10 bump itself, matching the sequence already proven in the sibling tanem/react-svg repo. It also differs in a few substantive ways:

  • react/jsx-sort-props is replaced by eslint-plugin-perfectionist's sort-jsx-props rather than dropped.
  • @eslint-react/naming-convention-ref-name and @eslint-react/use-state are fixed rather than turned off - refs are renamed to end in Ref, and useGetSetState's force-update moves to useReducer.
  • Hooks rules come from spreading eslint-plugin-react-hooks's recommended-latest, so react-hooks/refs is enabled with narrow per-site disables instead of a config-wide opt-out.
  • tsconfig.eslint.json is deleted, since it only existed to feed parserOptions.project and no type-aware rule used it.
  • lint gained --max-warnings=0, because @eslint-react's recommended config sets 38 rules at warn where the old plugin used error.

Closing in favour of that.

@tanem tanem closed this Jul 29, 2026
@tanem tanem added the internal label Jul 29, 2026
@tanem
tanem deleted the migrate-eslint-react-plugin branch August 1, 2026 00:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant