Skip to content

Conversation

karlhorky
Copy link
Contributor

Summary

The ESLint rule from eslint-plugin-react-compiler was merged into eslint-plugin-react-hooks in the following PR:

This PR adds documentation referencing the new react-hooks/react-compiler rule.

How did you test this change?

I wrote, edited and read the adaptations to the readme.

cc @poteto @michaelfaith

@meta-cla meta-cla bot added the CLA Signed label Aug 6, 2025
@react-sizebot
Copy link

Comparing: 66f09bd...8492dbe

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable/react-dom/cjs/react-dom.production.js = 6.68 kB 6.68 kB = 1.83 kB 1.83 kB
oss-stable/react-dom/cjs/react-dom-client.production.js = 530.04 kB 530.04 kB = 93.63 kB 93.63 kB
oss-experimental/react-dom/cjs/react-dom.production.js = 6.69 kB 6.69 kB = 1.83 kB 1.83 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js = 654.48 kB 654.48 kB = 115.34 kB 115.34 kB
facebook-www/ReactDOM-prod.classic.js = 674.42 kB 674.42 kB = 118.68 kB 118.68 kB
facebook-www/ReactDOM-prod.modern.js = 664.84 kB 664.84 kB = 117.02 kB 117.02 kB

Significant size changes

Includes any change greater than 0.2%:

(No significant changes)

Generated by 🚫 dangerJS against 8492dbe

@michaelfaith
Copy link
Contributor

Looks good to me. Thanks for contributing it!

@karlhorky
Copy link
Contributor Author

karlhorky commented Sep 28, 2025

I see that the new docs for react.dev in reactjs/react.dev#7986 (thanks @poteto!) and reactjs/react.dev#8005 (thanks @rickhanlonii!) are referring to many new rules (eg. error-boundaries and set-state-in-effect), omitting the react-hooks/react-compiler rule:

https://react.dev/reference/eslint-plugin-react-hooks

Screenshot 2025-09-28 at 14 40 36

These are seemingly being generated by code in babel-plugin-react-compiler:

function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
switch (category) {
case ErrorCategory.AutomaticEffectDependencies: {
return {
category,
severity: ErrorSeverity.Error,
name: 'automatic-effect-dependencies',
description:
'Verifies that automatic effect dependencies are compiled if opted-in',
recommended: false,
};
}
case ErrorCategory.CapitalizedCalls: {
return {
category,
severity: ErrorSeverity.Error,
name: 'capitalized-calls',
description:
'Validates against calling capitalized functions/methods instead of using JSX',
recommended: false,
};
}
case ErrorCategory.Config: {
return {
category,
severity: ErrorSeverity.Error,
name: 'config',
description: 'Validates the compiler configuration options',
recommended: true,
};
}
case ErrorCategory.EffectDependencies: {
return {
category,
severity: ErrorSeverity.Error,
name: 'memoized-effect-dependencies',
description: 'Validates that effect dependencies are memoized',
recommended: false,
};
}
case ErrorCategory.EffectDerivationsOfState: {
return {
category,
severity: ErrorSeverity.Error,
name: 'no-deriving-state-in-effects',
description:
'Validates against deriving values from state in an effect',
recommended: false,
};
}
case ErrorCategory.EffectSetState: {
return {
category,
severity: ErrorSeverity.Error,
name: 'set-state-in-effect',
description:
'Validates against calling setState synchronously in an effect, which can lead to re-renders that degrade performance',
recommended: true,
};
}
case ErrorCategory.ErrorBoundaries: {
return {
category,
severity: ErrorSeverity.Error,
name: 'error-boundaries',
description:
'Validates usage of error boundaries instead of try/catch for errors in child components',
recommended: true,
};
}
case ErrorCategory.Factories: {
return {
category,
severity: ErrorSeverity.Error,
name: 'component-hook-factories',
description:
'Validates against higher order functions defining nested components or hooks. ' +
'Components and hooks should be defined at the module level',
recommended: true,
};
}
case ErrorCategory.FBT: {
return {
category,
severity: ErrorSeverity.Error,
name: 'fbt',
description: 'Validates usage of fbt',
recommended: false,
};
}
case ErrorCategory.Fire: {
return {
category,
severity: ErrorSeverity.Error,
name: 'fire',
description: 'Validates usage of `fire`',
recommended: false,
};
}
case ErrorCategory.Gating: {
return {
category,
severity: ErrorSeverity.Error,
name: 'gating',
description:
'Validates configuration of [gating mode](https://react.dev/reference/react-compiler/gating)',
recommended: true,
};
}
case ErrorCategory.Globals: {
return {
category,
severity: ErrorSeverity.Error,
name: 'globals',
description:
'Validates against assignment/mutation of globals during render, part of ensuring that ' +
'[side effects must render outside of render](https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render)',
recommended: true,
};
}
case ErrorCategory.Hooks: {
return {
category,
severity: ErrorSeverity.Error,
name: 'hooks',
description: 'Validates the rules of hooks',
/**
* TODO: the "Hooks" rule largely reimplements the "rules-of-hooks" non-compiler rule.
* We need to dedeupe these (moving the remaining bits into the compiler) and then enable
* this rule.
*/
recommended: false,
};
}
case ErrorCategory.Immutability: {
return {
category,
severity: ErrorSeverity.Error,
name: 'immutability',
description:
'Validates against mutating props, state, and other values that [are immutable](https://react.dev/reference/rules/components-and-hooks-must-be-pure#props-and-state-are-immutable)',
recommended: true,
};
}
case ErrorCategory.Invariant: {
return {
category,
severity: ErrorSeverity.Error,
name: 'invariant',
description: 'Internal invariants',
recommended: false,
};
}
case ErrorCategory.PreserveManualMemo: {
return {
category,
severity: ErrorSeverity.Error,
name: 'preserve-manual-memoization',
description:
'Validates that existing manual memoized is preserved by the compiler. ' +
'React Compiler will only compile components and hooks if its inference ' +
'[matches or exceeds the existing manual memoization](https://react.dev/learn/react-compiler/introduction#what-should-i-do-about-usememo-usecallback-and-reactmemo)',
recommended: true,
};
}
case ErrorCategory.Purity: {
return {
category,
severity: ErrorSeverity.Error,
name: 'purity',
description:
'Validates that [components/hooks are pure](https://react.dev/reference/rules/components-and-hooks-must-be-pure) by checking that they do not call known-impure functions',
recommended: true,
};
}
case ErrorCategory.Refs: {
return {
category,
severity: ErrorSeverity.Error,
name: 'refs',
description:
'Validates correct usage of refs, not reading/writing during render. See the "pitfalls" section in [`useRef()` usage](https://react.dev/reference/react/useRef#usage)',
recommended: true,
};
}
case ErrorCategory.RenderSetState: {
return {
category,
severity: ErrorSeverity.Error,
name: 'set-state-in-render',
description:
'Validates against setting state during render, which can trigger additional renders and potential infinite render loops',
recommended: true,
};
}
case ErrorCategory.StaticComponents: {
return {
category,
severity: ErrorSeverity.Error,
name: 'static-components',
description:
'Validates that components are static, not recreated every render. Components that are recreated dynamically can reset state and trigger excessive re-rendering',
recommended: true,
};
}
case ErrorCategory.Suppression: {
return {
category,
severity: ErrorSeverity.Error,
name: 'rule-suppression',
description: 'Validates against suppression of other rules',
recommended: false,
};
}
case ErrorCategory.Syntax: {
return {
category,
severity: ErrorSeverity.Error,
name: 'syntax',
description: 'Validates against invalid syntax',
recommended: false,
};
}
case ErrorCategory.Todo: {
return {
category,
severity: ErrorSeverity.Hint,
name: 'todo',
description: 'Unimplemented features',
recommended: false,
};
}
case ErrorCategory.UnsupportedSyntax: {
return {
category,
severity: ErrorSeverity.Warning,
name: 'unsupported-syntax',
description:
'Validates against syntax that we do not plan to support in React Compiler',
recommended: true,
};
}
case ErrorCategory.UseMemo: {
return {
category,
severity: ErrorSeverity.Error,
name: 'use-memo',
description:
'Validates usage of the useMemo() hook against common mistakes. See [`useMemo()` docs](https://react.dev/reference/react/useMemo) for more information.',
recommended: true,
};
}
case ErrorCategory.IncompatibleLibrary: {
return {
category,
severity: ErrorSeverity.Warning,
name: 'incompatible-library',
description:
'Validates against usage of libraries which are incompatible with memoization (manual or automatic)',
recommended: true,
};
}
default: {
assertExhaustive(category, `Unsupported category ${category}`);
}
}
}

So maybe my PR here is obsolete? And the readme for eslint-plugin-react-hooks should include references to those new rules instead of react-hooks/react-compiler?

@josephsavona
Copy link
Member

Yup, we broke up the rule into distinct rules (that share a single invocation of the compiler) to help provide more targeted feedback. I think it makes sense to close this, and we can make adjustments to the docs as necessary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants