Skip to content

Commit f0e5627

Browse files
committed
[lint] Use settings for additional hooks in exhaustive deps
1 parent d08f2e4 commit f0e5627

File tree

2 files changed

+109
-4
lines changed

2 files changed

+109
-4
lines changed

packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,6 +1485,70 @@ const tests = {
14851485
}
14861486
`,
14871487
},
1488+
{
1489+
// Test settings-based additionalHooks - should work with settings
1490+
code: normalizeIndent`
1491+
function MyComponent(props) {
1492+
useCustomEffect(() => {
1493+
console.log(props.foo);
1494+
});
1495+
}
1496+
`,
1497+
settings: {
1498+
'react-eslint': {
1499+
additionalEffectHooks: 'useCustomEffect',
1500+
},
1501+
},
1502+
},
1503+
{
1504+
// Test settings-based additionalHooks - should work with dependencies
1505+
code: normalizeIndent`
1506+
function MyComponent(props) {
1507+
useCustomEffect(() => {
1508+
console.log(props.foo);
1509+
}, [props.foo]);
1510+
}
1511+
`,
1512+
settings: {
1513+
'react-eslint': {
1514+
additionalEffectHooks: 'useCustomEffect',
1515+
},
1516+
},
1517+
},
1518+
{
1519+
// Test that rule-level additionalHooks takes precedence over settings
1520+
code: normalizeIndent`
1521+
function MyComponent(props) {
1522+
useCustomEffect(() => {
1523+
console.log(props.foo);
1524+
}, []);
1525+
}
1526+
`,
1527+
options: [{additionalHooks: 'useAnotherEffect'}],
1528+
settings: {
1529+
'react-eslint': {
1530+
additionalEffectHooks: 'useCustomEffect',
1531+
},
1532+
},
1533+
},
1534+
{
1535+
// Test settings with multiple hooks pattern
1536+
code: normalizeIndent`
1537+
function MyComponent(props) {
1538+
useCustomEffect(() => {
1539+
console.log(props.foo);
1540+
}, [props.foo]);
1541+
useAnotherEffect(() => {
1542+
console.log(props.bar);
1543+
}, [props.bar]);
1544+
}
1545+
`,
1546+
settings: {
1547+
'react-eslint': {
1548+
additionalEffectHooks: '(useCustomEffect|useAnotherEffect)',
1549+
},
1550+
},
1551+
},
14881552
],
14891553
invalid: [
14901554
{
@@ -3714,6 +3778,40 @@ const tests = {
37143778
},
37153779
],
37163780
},
3781+
{
3782+
// Test settings-based additionalHooks - should detect missing dependency
3783+
code: normalizeIndent`
3784+
function MyComponent(props) {
3785+
useCustomEffect(() => {
3786+
console.log(props.foo);
3787+
}, []);
3788+
}
3789+
`,
3790+
settings: {
3791+
'react-eslint': {
3792+
additionalEffectHooks: 'useCustomEffect',
3793+
},
3794+
},
3795+
errors: [
3796+
{
3797+
message:
3798+
"React Hook useCustomEffect has a missing dependency: 'props.foo'. " +
3799+
'Either include it or remove the dependency array.',
3800+
suggestions: [
3801+
{
3802+
desc: 'Update the dependencies array to be: [props.foo]',
3803+
output: normalizeIndent`
3804+
function MyComponent(props) {
3805+
useCustomEffect(() => {
3806+
console.log(props.foo);
3807+
}, [props.foo]);
3808+
}
3809+
`,
3810+
},
3811+
],
3812+
},
3813+
],
3814+
},
37173815
{
37183816
code: normalizeIndent`
37193817
function MyComponent() {

packages/eslint-plugin-react-hooks/src/rules/ExhaustiveDeps.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,19 +69,25 @@ const rule = {
6969
},
7070
requireExplicitEffectDeps: {
7171
type: 'boolean',
72-
}
72+
},
7373
},
7474
},
7575
],
7676
},
7777
create(context: Rule.RuleContext) {
7878
const rawOptions = context.options && context.options[0];
79+
const settings = context.settings || {};
80+
7981

8082
// Parse the `additionalHooks` regex.
83+
// Use rule-level additionalHooks if provided, otherwise fall back to settings
8184
const additionalHooks =
8285
rawOptions && rawOptions.additionalHooks
8386
? new RegExp(rawOptions.additionalHooks)
84-
: undefined;
87+
: settings['react-eslint'] &&
88+
settings['react-eslint'].additionalEffectHooks
89+
? new RegExp(settings['react-eslint'].additionalEffectHooks)
90+
: undefined;
8591

8692
const enableDangerousAutofixThisMayCauseInfiniteLoops: boolean =
8793
(rawOptions &&
@@ -93,7 +99,8 @@ const rule = {
9399
? rawOptions.experimental_autoDependenciesHooks
94100
: [];
95101

96-
const requireExplicitEffectDeps: boolean = rawOptions && rawOptions.requireExplicitEffectDeps || false;
102+
const requireExplicitEffectDeps: boolean =
103+
(rawOptions && rawOptions.requireExplicitEffectDeps) || false;
97104

98105
const options = {
99106
additionalHooks,
@@ -1351,7 +1358,7 @@ const rule = {
13511358
node: reactiveHook,
13521359
message:
13531360
`React Hook ${reactiveHookName} always requires dependencies. ` +
1354-
`Please add a dependency array or an explicit \`undefined\``
1361+
`Please add a dependency array or an explicit \`undefined\``,
13551362
});
13561363
}
13571364

0 commit comments

Comments
 (0)