Improve lint error messages for useEffectEvent (#34669)
Called Before: > `logEvent` is a function created with React Hook "useEffectEvent", and can only be called from the same component. Called After: > `logEvent` is a function created with React Hook "useEffectEvent", and can only be called from Effects and Effect Events in the same component. Referenced Before: > `logEvent` is a function created with React Hook "useEffectEvent", and can only be called from the same component. They cannot be assigned to variables or passed down. Referenced After: > `logEvent` is a function created with React Hook "useEffectEvent", and can only be called from Effects and Effect Events in the same component. It cannot be assigned to a variable or passed down.
Jack Pope committed
Oct 1, 2025 at 15:17 UTC
67e24bc5279204108b749fe48b4d395ef9e49e67
2 files changed
+33
-11
packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js
+19
-3
@@ -1637,17 +1637,32 @@ const allTests = {
1637
const onClick = useEffectEvent(() => {
1638
showNotification(theme);
1639
});
1640
+ // error message 1
1641
const onClick2 = () => { onClick() };
1642
+ // error message 2
1643
const onClick3 = useCallback(() => onClick(), []);
1644
+ // error message 3
1645
+ const onClick4 = onClick;
1646
return <>
1647
+ {/** error message 4 */}
1648
+ <Child onClick={onClick}></Child>
1649
<Child onClick={onClick2}></Child>
1650
<Child onClick={onClick3}></Child>
1651
</>;
1652
}
1653
`,
1654
+ // Explicitly test error messages here for various cases
1655
errors: [
1649
- useEffectEventError('onClick', true),
1650
- useEffectEventError('onClick', true),
1656
+ `\`onClick\` is a function created with React Hook "useEffectEvent", and can only be called from ` +
1657
+ 'Effects and Effect Events in the same component.',
1658
+ `\`onClick\` is a function created with React Hook "useEffectEvent", and can only be called from ` +
1659
+ 'Effects and Effect Events in the same component.',
1660
+ `\`onClick\` is a function created with React Hook "useEffectEvent", and can only be called from ` +
1661
+ `Effects and Effect Events in the same component. ` +
1662
+ `It cannot be assigned to a variable or passed down.`,
1663
+ `\`onClick\` is a function created with React Hook "useEffectEvent", and can only be called from ` +
1664
+ `Effects and Effect Events in the same component. ` +
1665
+ `It cannot be assigned to a variable or passed down.`,
1666
],
1667
},
1668
],
@@ -1714,7 +1729,8 @@ function useEffectEventError(fn, called) {
1729
return {
1730
message:
1731
`\`${fn}\` is a function created with React Hook "useEffectEvent", and can only be called from ` +
1717
- `the same component.${called ? '' : ' They cannot be assigned to variables or passed down.'}`,
1732
+ 'Effects and Effect Events in the same component.' +
1733
+ (called ? '' : ' It cannot be assigned to a variable or passed down.'),
1734
};
1735
}
1736
packages/eslint-plugin-react-hooks/src/rules/RulesOfHooks.ts
+14
-8
@@ -166,10 +166,19 @@ function isEffectIdentifier(node: Node, additionalHooks?: RegExp): boolean {
166
167
return false;
168
}
169
+
170
function isUseEffectEventIdentifier(node: Node): boolean {
171
return node.type === 'Identifier' && node.name === 'useEffectEvent';
172
}
173
174
+function useEffectEventError(fn: string, called: boolean): string {
175
+ return (
176
+ `\`${fn}\` is a function created with React Hook "useEffectEvent", and can only be called from ` +
177
+ 'Effects and Effect Events in the same component.' +
178
+ (called ? '' : ' It cannot be assigned to a variable or passed down.')
179
+ );
180
+}
181
+
182
function isUseIdentifier(node: Node): boolean {
183
return isReactFunction(node, 'use');
184
}
@@ -769,14 +778,11 @@ const rule = {
778
// This identifier resolves to a useEffectEvent function, but isn't being referenced in an
779
// effect or another event function. It isn't being called either.
780
if (lastEffect == null && useEffectEventFunctions.has(node)) {
772
- const message =
773
- `\`${getSourceCode().getText(
774
- node,
775
- )}\` is a function created with React Hook "useEffectEvent", and can only be called from ` +
776
- 'the same component.' +
777
- (node.parent.type === 'CallExpression'
778
- ? ''
779
- : ' They cannot be assigned to variables or passed down.');
781
+ const message = useEffectEventError(
782
+ getSourceCode().getText(node),
783
+ node.parent.type === 'CallExpression',
784
+ );
785
+
786
context.report({
787
node,
788
message,