github Rel1cx/eslint-react v3.0.0-beta
v3.0.0-beta.33 (2026-02-22)

latest release: v3.0.0-beta.33
pre-release4 hours ago

What's Changed

๐Ÿ’ฅ Breaking Changes

Minimum Node.js version raised from 20 to 22

The minimum required Node.js version is now >=22.0.0 (previously >=20.19.0).

Consolidated and removed rules in eslint-plugin-react-x

Old Rule (react-x/) New Rule (react-x/) Change
jsx-no-iife unsupported-syntax consolidated
jsx-no-undef โ€” removed
no-unnecessary-key โ€” removed
no-useless-forward-ref no-forward-ref consolidated
prefer-read-only-props immutability consolidated
prefer-use-state-lazy-initialization use-state consolidated
  • jsx-no-iife: The IIFE-in-JSX check has been merged into the new unsupported-syntax rule, which also covers eval and with statements.
  • jsx-no-undef: ESLint v10.0.0 now tracks JSX references natively, making this rule redundant. The no-undef rule now correctly handles JSX element references.
  • no-unnecessary-key: The experimental rule has been removed.
  • no-useless-forward-ref: Consolidated into no-forward-ref. Since React 19, forwardRef is no longer necessary as ref can be passed as a prop. The no-forward-ref rule now covers all forwardRef usage patterns.
  • prefer-read-only-props: The TypeScript-based read-only props enforcement has been consolidated into the new immutability rule, which covers a broader set of immutability violations, including in-place array mutations and direct property assignments on state and props.
  • prefer-use-state-lazy-initialization: Its lazy-initialization checks are now part of the use-state rule and controlled by the new enforceLazyInitialization option (default: true).

Removed previously deprecated rules

Rule Deprecated in Package Replacement
no-default-props 2.9.3 eslint-plugin-react-x no-restricted-syntax
no-forbidden-props 2.3.2 eslint-plugin-react-x no-restricted-syntax
no-prop-types 2.9.3 eslint-plugin-react-x no-restricted-syntax
no-string-refs 2.9.3 eslint-plugin-react-x no-restricted-syntax
no-unnecessary-use-ref 2.10.0 eslint-plugin-react-x
filename 2.13.0 eslint-plugin-react-naming-convention
filename-extension 2.13.0 eslint-plugin-react-naming-convention

Removed eslint-plugin-react-hooks-extra package

All rules have been migrated into eslint-plugin-react-x:

Old Rule (react-hooks-extra/) New Rule (react-x/) Change
no-direct-set-state-in-use-effect set-state-in-effect relocated, renamed

Preset changes

Change Rule Presets affected Severity / Notes
Removed react-x/no-default-props recommended, x removed
Removed react-x/no-prop-types recommended, x removed
Removed react-x/no-string-refs recommended, x removed
Removed @eslint-react/hooks-extra/* recommended, all (in @eslint-react/eslint-plugin) removed
Added react-x/component-hook-factories recommended, x error
Added react-x/error-boundaries recommended, x error
Added react-x/exhaustive-deps recommended, x warn
Added react-x/use-memo recommended, x error
Moved react-naming-convention/use-state โ†’ react-x/use-state recommended, x warn
Added react-x/rules-of-hooks recommended, x error
Added react-x/set-state-in-effect recommended, x warn
Added react-x/set-state-in-render recommended, x error
Added react-x/unsupported-syntax recommended, x error
Removed react-x/jsx-no-iife strict, disable-experimental, all merged into unsupported-syntax
Removed react-x/jsx-no-undef all ESLint v10.0.0+ native support
Removed react-x/no-useless-forward-ref recommended, x, all merged into no-forward-ref
Removed react-x/prefer-read-only-props disable-experimental, disable-type-checked consolidated into immutability
Removed react-x/prefer-use-state-lazy-initialization recommended, x, all merged into use-state

โœจ New

Added the following new rules to eslint-plugin-react-x:

  • component-hook-factories: Validates against higher-order functions defining nested components or hooks. Components and hooks should be defined at the module level.
  • error-boundaries: Validates usage of Error Boundaries instead of try/catch for errors in child components. Try/catch blocks can't catch errors during React's rendering process โ€” only Error Boundaries can catch these errors. Contributed by @Rel1cx in #1506
  • exhaustive-deps: Enforces that React hook dependency arrays contain all reactive values used in the callback. Contributed by @TrevorBurnham in #1499
  • immutability (Experimental): Validates against mutating props, state, and other values that are immutable. Detects in-place array mutations (e.g., push, sort, splice) and direct property assignments on state variables from useState and props objects. Mirrors the immutability lint rule described in the React docs.
  • purity (Experimental): Validates that components and hooks are pure by checking that they do not call known-impure functions during render.
  • refs (Experimental): Validates correct usage of refs by checking that ref.current is not read or written during render. See the "pitfalls" section in useRef().
  • rules-of-hooks: Enforces the Rules of Hooks. Contributed by @TrevorBurnham in #1499
  • set-state-in-effect: Validates against calling setState synchronously in an effect, which can lead to re-renders that degrade performance. Contributed by @Rel1cx

    Compared to the old no-direct-set-state-in-use-effect rule, the new set-state-in-effect rule allows setting state in effects if the value is from a ref. All other behaviors remain the same.

    The following example from the React Docs demonstrates that setState in an effect is fine if the value comes from a ref, since it cannot be calculated during rendering:

    import { useLayoutEffect, useRef, useState } from "react";
    
    function Tooltip() {
      const ref = useRef(null);
      const [tooltipHeight, setTooltipHeight] = useState(0);
    
      useLayoutEffect(() => {
        const { height } = ref.current.getBoundingClientRect();
        setTooltipHeight(height);
      }, []);
      // ...
    }
  • use-memo: Validates that useMemo is called with a callback that returns a value. useMemo is designed for computing and caching values โ€” without a return value it always returns undefined, which defeats its purpose. This rule also catches useMemo calls whose return value is discarded (not assigned to a variable), which indicates a side-effect misuse that should use useEffect instead. Mirrors the use-memo lint rule described in the React docs.
  • use-state: Enforces correct usage of the useState hook โ€” destructuring, symmetric naming of the value and setter (e.g., count / setCount), and lazy initialization of expensive initial state. Moved from eslint-plugin-react-naming-convention into eslint-plugin-react-x so that all hook-usage rules live in one package. The lazy-initialization behavior (previously prefer-use-state-lazy-initialization) is now also part of this rule and controlled by the enforceLazyInitialization option (default: true).
  • set-state-in-render (Experimental): Validates against unconditionally setting state during render, which can trigger additional renders and potential infinite render loops. Contributed by @Rel1cx in #1501
  • unsupported-syntax: Validates against syntax that React Compiler does not support, including eval, with statements, and IIFEs in JSX (previously covered by jsx-no-iife).

Added compilationMode setting:

Added support for the compilationMode setting under settings["react-x"]. This setting informs rules about the React Compiler compilation mode the project is using, allowing rules to understand how components and hooks will be picked up by the compiler. Accepted values are "off", "infer", "annotation", "syntax", and "all" (default: "annotation"). When set to anything other than "off", the compiler is considered enabled.

๐Ÿช„ Improvements

  • Adopted tsl for type checking across the monorepo, improving linting performance. Contributed by @Rel1cx in #1532
  • Directly ported eslint-plugin-react-hooks rules (rules-of-hooks and exhaustive-deps) with code-path analysis for more accurate hook validation. Contributed by @Rel1cx in #1535
  • Improved set-state-in-effect rule to allow setState calls when the new state is derived from refs (aligning with React's recommended patterns). Contributed by @Rel1cx in #1521
  • Improved detection of React components created via conditional (ternary) expressions (e.g., const Component = condition ? () => <A/> : () => <B/>) in function-component and no-nested-component-definitions rules. Contributed by @Rel1cx in #1503
  • Refactored core modules to use defineRuleListener helper for more consistent rule listener definitions across all rules. Contributed by @Rel1cx in #1517
  • Restructured and consolidated component detection modules for better maintainability and accuracy. Contributed by @Rel1cx
  • Restructured core, var, and ast utility modules for improved code organization. Contributed by @Rel1cx in #1520
  • Updated documentation with standardized "See Also" sections and unified "Further Reading" sections across all rule documentation. Contributed by @Rel1cx in #1536 and #1537

โœ… Upgrade Checklist

Use this checklist to upgrade from v2.x to v3.0.0:

Node.js

  • Upgrade Node.js to >=22.0.0 (previously >=20.19.0).

Package changes

  • Remove eslint-plugin-react-hooks-extra from your package.json โ€” this package is no longer published.
  • If you were importing eslint-plugin-react-hooks-extra directly, replace it with eslint-plugin-react-x.

ESLint configuration

  • Replace react-hooks-extra/no-direct-set-state-in-use-effect with react-x/set-state-in-effect in your ESLint config.
  • Replace react-naming-convention/use-state (or @eslint-react/naming-convention/use-state) with react-x/use-state (or @eslint-react/use-state) in your ESLint config.
  • Remove any @eslint-react/hooks-extra/* rules from your config โ€” these have been removed from @eslint-react/eslint-plugin.
  • Remove references to the following deleted rules (use no-restricted-syntax instead if needed):
    • react-x/no-default-props
    • react-x/no-forbidden-props
    • react-x/no-prop-types
    • react-x/no-string-refs
  • Remove react-x/jsx-no-iife from your config if present โ€” this rule has been consolidated into react-x/unsupported-syntax.
  • Remove react-x/jsx-no-undef from your config if present โ€” this rule has been removed since ESLint v10.0.0 now tracks JSX references natively.
  • Remove react-x/no-unnecessary-key from your config if present โ€” this rule has been deleted with no replacement.
  • Remove react-x/no-unnecessary-use-ref from your config if present โ€” this rule has been deleted with no replacement.
  • Remove react-x/no-useless-forward-ref from your config if present โ€” this rule has been consolidated into react-x/no-forward-ref.
  • Remove react-x/prefer-read-only-props from your config if present โ€” this rule has been consolidated into react-x/immutability.
  • Remove react-x/prefer-use-state-lazy-initialization from your config if present โ€” this rule has been consolidated into react-x/use-state and its lazy-initialization checks are now controlled by the enforceLazyInitialization option.
  • Remove react-naming-convention/filename and react-naming-convention/filename-extension from your config if present โ€” these rules have been deleted with no replacement.

Review new rules enabled in presets

If you use the recommended, x, or all preset, the following rules are now included automatically. Review your codebase for new reports:

  • react-x/component-hook-factories (error) โ€” catches factory functions that define components or hooks inside them instead of at the module level.
  • react-x/error-boundaries (error) โ€” catches try/catch blocks wrapping JSX or use hook calls where Error Boundaries should be used instead.
  • react-x/exhaustive-deps (warn) โ€” enforces that hook dependency arrays contain all reactive values.
  • react-x/purity (warn) โ€” validates that components and hooks are pure by checking that they do not call known-impure functions during render.
  • react-x/rules-of-hooks (error) โ€” enforces the Rules of Hooks.
  • react-x/set-state-in-effect (warn) โ€” catches synchronous setState calls inside effects.
  • react-x/set-state-in-render (error) โ€” catches unconditional setState calls during render that can cause infinite loops.
  • react-x/unsupported-syntax (error) โ€” catches usage of syntax that React Compiler does not support, including eval, with statements, and IIFEs in JSX.
  • react-x/use-memo (error) โ€” catches useMemo calls where the callback has no return value or where the useMemo return value is discarded.
  • react-x/use-state (warn) โ€” Enforces correct usage of useState, including destructuring, symmetric naming of the value and setter (previously react-naming-convention/use-state), and wrapping expensive initializers in a lazy initializer function (previously prefer-use-state-lazy-initialization).

๐Ÿ“˜ Migration Guide: From eslint-plugin-react-hooks

ESLint React now provides direct equivalents for the core rules in eslint-plugin-react-hooks, including both the classic hooks linting rules (exhaustive-deps, rules-of-hooks) and many of the newer React Compiler diagnostic rules.

eslint-plugin-react-hooks Rule ESLint React Equivalent Status
exhaustive-deps react-x/exhaustive-deps ๐Ÿ”ง Auto-fixable
rules-of-hooks react-x/rules-of-hooks ๐Ÿ”ง Auto-fixable
component-hook-factories react-x/component-hook-factories โœ… Supported
error-boundaries react-x/error-boundaries โœ… Supported
immutability react-x/immutability ๐ŸŸก ๐Ÿงช Experimental
purity react-x/purity ๐ŸŸก ๐Ÿงช Experimental
refs react-x/refs ๐ŸŸก ๐Ÿงช Experimental
set-state-in-effect react-x/set-state-in-effect โœ… Supported
set-state-in-render react-x/set-state-in-render ๐Ÿงช Experimental
static-components react-x/no-nested-component-definitions โœ… Supported
unsupported-syntax react-x/unsupported-syntax โœ… Supported
use-memo react-x/use-memo โœ… Supported

Legend: ๐Ÿ”ง Fully supported with auto-fix โ€” โœ… Mostly supported โ€” ๐ŸŸก Partial support โ€” ๐Ÿงช Experimental

Note: React Compiler-specific rules (config, gating, globals, incompatible-library, preserve-manual-memoization) do not have equivalents in ESLint React, as they validate compiler-specific configuration and behavior.

See the complete migration guide for more details.

Full Changelog: v2.13.0...v3.0.0-beta.33

Don't miss a new eslint-react release

NewReleases is sending notifications on new releases.