Skip to content

Commit 7ab4adb

Browse files
committed
refactor(plugins/hooks-extra): improve code readability in 'no-direct-set-state-in-use-effect'
1 parent 26c7b8f commit 7ab4adb

File tree

2 files changed

+55
-44
lines changed

2 files changed

+55
-44
lines changed

packages/plugins/eslint-plugin-react-hooks-extra/src/rules/no-direct-set-state-in-use-effect.ts

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -45,29 +45,34 @@ export default createRule<[], MessageID>({
4545
if (!/use\w*Effect/u.test(context.sourceCode.text)) return {};
4646
const settings = decodeSettings(context.settings);
4747
const additionalHooks = settings.additionalHooks ?? {};
48+
4849
const isUseEffectLikeCall = isReactHookCallWithNameAlias("useEffect", context, additionalHooks.useEffect ?? []);
4950
const isUseStateCall = isReactHookCallWithNameAlias("useState", context, additionalHooks.useState ?? []);
5051
const isUseMemoCall = isReactHookCallWithNameAlias("useMemo", context, additionalHooks.useMemo ?? []);
5152
const isUseCallbackCall = isReactHookCallWithNameAlias("useCallback", context, additionalHooks.useCallback ?? []);
5253
const isSetStateCall = isSetFunctionCall(context, settings);
5354
const isIdFromUseStateCall = isFromUseStateCall(context, settings);
55+
5456
const functionStack: [node: AST.TSESTreeFunction, kind: FunctionKind][] = [];
5557
const setupFunctionRef = { current: O.none<AST.TSESTreeFunction>() };
5658
const setupFunctionIdentifiers: TSESTree.Identifier[] = [];
57-
const indirectFunctionCalls: TSESTree.CallExpression[] = [];
58-
const indirectSetStateCalls = new WeakMap<AST.TSESTreeFunction, TSESTree.CallExpression[]>();
59-
const indirectSetStateCallsAsArgs = new WeakMap<TSESTree.CallExpression, TSESTree.Identifier[]>();
60-
const indirectSetStateCallsAsSetups = new Map<TSESTree.CallExpression, TSESTree.Identifier[]>();
61-
const indirectSetStateCallsInHooks = new WeakMap<
59+
60+
const indFunctionCalls: TSESTree.CallExpression[] = [];
61+
const indSetStateCalls = new WeakMap<AST.TSESTreeFunction, TSESTree.CallExpression[]>();
62+
const indSetStateCallsInUseEffectArg0 = new WeakMap<TSESTree.CallExpression, TSESTree.Identifier[]>();
63+
const indSetStateCallsInUseEffectSetup = new Map<TSESTree.CallExpression, TSESTree.Identifier[]>();
64+
const indSetStateCallsInUseMemoOrCallback = new WeakMap<
6265
TSESTree.VariableDeclarator["init"] & {},
6366
TSESTree.CallExpression[]
6467
>();
68+
6569
const onSetupFunctionEnter = (node: AST.TSESTreeFunction) => {
6670
setupFunctionRef.current = O.some(node);
6771
};
6872
const onSetupFunctionExit = (node: AST.TSESTreeFunction) => {
6973
setupFunctionRef.current = O.filter(setupFunctionRef.current, (current) => current !== node);
7074
};
75+
7176
function isSetupFunction(node: TSESTree.Node) {
7277
return node.parent?.type === AST_NODE_TYPES.CallExpression
7378
&& node.parent.callee !== node
@@ -109,12 +114,12 @@ export default createRule<[], MessageID>({
109114
const maybeVd = AST.traverseUpGuard(node, isVariableDeclaratorFromHookCall);
110115
if (O.isSome(maybeVd)) {
111116
const vd = maybeVd.value;
112-
const calls = indirectSetStateCallsInHooks.get(vd.init) ?? [];
113-
indirectSetStateCallsInHooks.set(vd.init, [...calls, node]);
117+
const calls = indSetStateCallsInUseMemoOrCallback.get(vd.init) ?? [];
118+
indSetStateCallsInUseMemoOrCallback.set(vd.init, [...calls, node]);
114119
return;
115120
}
116-
const calls = indirectSetStateCalls.get(parentFn) ?? [];
117-
indirectSetStateCalls.set(parentFn, [...calls, node]);
121+
const calls = indSetStateCalls.get(parentFn) ?? [];
122+
indSetStateCalls.set(parentFn, [...calls, node]);
118123
return;
119124
}
120125
context.report({
@@ -133,7 +138,7 @@ export default createRule<[], MessageID>({
133138
.with("other", () => {
134139
const isInSetupFunction = effectFn === parentFn;
135140
if (!isInSetupFunction) return;
136-
indirectFunctionCalls.push(node);
141+
indFunctionCalls.push(node);
137142
})
138143
.otherwise(F.constVoid);
139144
},
@@ -151,8 +156,8 @@ export default createRule<[], MessageID>({
151156
const maybeVd = AST.traverseUpGuard(parent, isVariableDeclaratorFromHookCall);
152157
if (O.isNone(maybeVd)) break;
153158
const vd = maybeVd.value;
154-
const calls = indirectSetStateCallsAsArgs.get(vd.init) ?? [];
155-
indirectSetStateCallsAsArgs.set(vd.init, [...calls, node]);
159+
const calls = indSetStateCallsInUseEffectArg0.get(vd.init) ?? [];
160+
indSetStateCallsInUseEffectArg0.set(vd.init, [...calls, node]);
156161
break;
157162
}
158163
case AST_NODE_TYPES.CallExpression: {
@@ -165,14 +170,14 @@ export default createRule<[], MessageID>({
165170
const maybeVd = AST.traverseUpGuard(node.parent, isVariableDeclaratorFromHookCall);
166171
if (O.isNone(maybeVd)) break;
167172
const vd = maybeVd.value;
168-
const calls = indirectSetStateCallsAsArgs.get(vd.init) ?? [];
169-
indirectSetStateCallsAsArgs.set(vd.init, [...calls, node]);
173+
const calls = indSetStateCallsInUseEffectArg0.get(vd.init) ?? [];
174+
indSetStateCallsInUseEffectArg0.set(vd.init, [...calls, node]);
170175
}
171176
// const [state, setState] = useState();
172177
// useEffect(setState);
173178
if (isUseEffectLikeCall(node.parent)) {
174-
const calls = indirectSetStateCallsAsArgs.get(node.parent) ?? [];
175-
indirectSetStateCallsAsSetups.set(node.parent, [...calls, node]);
179+
const calls = indSetStateCallsInUseEffectArg0.get(node.parent) ?? [];
180+
indSetStateCallsInUseEffectSetup.set(node.parent, [...calls, node]);
176181
}
177182
break;
178183
}
@@ -188,13 +193,13 @@ export default createRule<[], MessageID>({
188193
case AST_NODE_TYPES.ArrowFunctionExpression:
189194
case AST_NODE_TYPES.FunctionDeclaration:
190195
case AST_NODE_TYPES.FunctionExpression:
191-
return indirectSetStateCalls.get(node) ?? [];
196+
return indSetStateCalls.get(node) ?? [];
192197
case AST_NODE_TYPES.CallExpression:
193-
return indirectSetStateCallsInHooks.get(node) ?? indirectSetStateCallsAsArgs.get(node) ?? [];
198+
return indSetStateCallsInUseMemoOrCallback.get(node) ?? indSetStateCallsInUseEffectArg0.get(node) ?? [];
194199
}
195200
return [];
196201
};
197-
for (const [_, calls] of indirectSetStateCallsAsSetups) {
202+
for (const [_, calls] of indSetStateCallsInUseEffectSetup) {
198203
for (const call of calls) {
199204
context.report({
200205
messageId: "noDirectSetStateInUseEffect",
@@ -203,7 +208,7 @@ export default createRule<[], MessageID>({
203208
});
204209
}
205210
}
206-
for (const { callee } of indirectFunctionCalls) {
211+
for (const { callee } of indFunctionCalls) {
207212
if (!("name" in callee)) continue;
208213
const { name } = callee;
209214
const setStateCalls = getSetStateCalls(name, context.sourceCode.getScope(callee));

packages/plugins/eslint-plugin-react-hooks-extra/src/rules/no-direct-set-state-in-use-layout-effect.ts

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ export default createRule<[], MessageID>({
4646
if (!/use\w*Effect/u.test(context.sourceCode.text)) return {};
4747
const settings = decodeSettings(context.settings);
4848
const additionalHooks = settings.additionalHooks ?? {};
49-
const isUseEffectLikeCall = isReactHookCallWithNameAlias(
49+
50+
const isUseLayoutEffectLikeCall = isReactHookCallWithNameAlias(
5051
"useLayoutEffect",
5152
context,
5253
additionalHooks.useLayoutEffect ?? [],
@@ -56,32 +57,36 @@ export default createRule<[], MessageID>({
5657
const isUseCallbackCall = isReactHookCallWithNameAlias("useCallback", context, additionalHooks.useCallback ?? []);
5758
const isSetStateCall = isSetFunctionCall(context, settings);
5859
const isIdFromUseStateCall = isFromUseStateCall(context, settings);
60+
5961
const functionStack: [node: AST.TSESTreeFunction, kind: FunctionKind][] = [];
6062
const setupFunctionRef = { current: O.none<AST.TSESTreeFunction>() };
6163
const setupFunctionIdentifiers: TSESTree.Identifier[] = [];
62-
const indirectFunctionCalls: TSESTree.CallExpression[] = [];
63-
const indirectSetStateCalls = new WeakMap<AST.TSESTreeFunction, TSESTree.CallExpression[]>();
64-
const indirectSetStateCallsAsArgs = new WeakMap<TSESTree.CallExpression, TSESTree.Identifier[]>();
65-
const indirectSetStateCallsAsSetups = new Map<TSESTree.CallExpression, TSESTree.Identifier[]>();
66-
const indirectSetStateCallsInHooks = new WeakMap<
64+
65+
const indFunctionCalls: TSESTree.CallExpression[] = [];
66+
const indSetStateCalls = new WeakMap<AST.TSESTreeFunction, TSESTree.CallExpression[]>();
67+
const indSetStateCallsInUseLayoutEffectArg0 = new WeakMap<TSESTree.CallExpression, TSESTree.Identifier[]>();
68+
const indSetStateCallsInUseLayoutEffectSetup = new Map<TSESTree.CallExpression, TSESTree.Identifier[]>();
69+
const indSetStateCallsInUseMemoOrCallback = new WeakMap<
6770
TSESTree.VariableDeclarator["init"] & {},
6871
TSESTree.CallExpression[]
6972
>();
73+
7074
const onSetupFunctionEnter = (node: AST.TSESTreeFunction) => {
7175
setupFunctionRef.current = O.some(node);
7276
};
7377
const onSetupFunctionExit = (node: AST.TSESTreeFunction) => {
7478
setupFunctionRef.current = O.filter(setupFunctionRef.current, (current) => current !== node);
7579
};
80+
7681
function isSetupFunction(node: TSESTree.Node) {
7782
return node.parent?.type === AST_NODE_TYPES.CallExpression
7883
&& node.parent.callee !== node
79-
&& isUseEffectLikeCall(node.parent);
84+
&& isUseLayoutEffectLikeCall(node.parent);
8085
}
8186
function getCallKind(node: TSESTree.CallExpression) {
8287
return match<TSESTree.CallExpression, CallKind>(node)
8388
.when(isUseStateCall, () => "useState")
84-
.when(isUseEffectLikeCall, () => "useLayoutEffect")
89+
.when(isUseLayoutEffectLikeCall, () => "useLayoutEffect")
8590
.when(isSetStateCall, () => "setState")
8691
.when(isThenCall, () => "then")
8792
.otherwise(() => "other");
@@ -114,12 +119,12 @@ export default createRule<[], MessageID>({
114119
const maybeVd = AST.traverseUpGuard(node, isVariableDeclaratorFromHookCall);
115120
if (O.isSome(maybeVd)) {
116121
const vd = maybeVd.value;
117-
const calls = indirectSetStateCallsInHooks.get(vd.init) ?? [];
118-
indirectSetStateCallsInHooks.set(vd.init, [...calls, node]);
122+
const calls = indSetStateCallsInUseMemoOrCallback.get(vd.init) ?? [];
123+
indSetStateCallsInUseMemoOrCallback.set(vd.init, [...calls, node]);
119124
return;
120125
}
121-
const calls = indirectSetStateCalls.get(parentFn) ?? [];
122-
indirectSetStateCalls.set(parentFn, [...calls, node]);
126+
const calls = indSetStateCalls.get(parentFn) ?? [];
127+
indSetStateCalls.set(parentFn, [...calls, node]);
123128
return;
124129
}
125130
context.report({
@@ -138,7 +143,7 @@ export default createRule<[], MessageID>({
138143
.with("other", () => {
139144
const isInSetupFunction = effectFn === parentFn;
140145
if (!isInSetupFunction) return;
141-
indirectFunctionCalls.push(node);
146+
indFunctionCalls.push(node);
142147
})
143148
.otherwise(F.constVoid);
144149
},
@@ -156,8 +161,8 @@ export default createRule<[], MessageID>({
156161
const maybeVd = AST.traverseUpGuard(parent, isVariableDeclaratorFromHookCall);
157162
if (O.isNone(maybeVd)) break;
158163
const vd = maybeVd.value;
159-
const calls = indirectSetStateCallsAsArgs.get(vd.init) ?? [];
160-
indirectSetStateCallsAsArgs.set(vd.init, [...calls, node]);
164+
const calls = indSetStateCallsInUseLayoutEffectArg0.get(vd.init) ?? [];
165+
indSetStateCallsInUseLayoutEffectArg0.set(vd.init, [...calls, node]);
161166
break;
162167
}
163168
case AST_NODE_TYPES.CallExpression: {
@@ -170,14 +175,14 @@ export default createRule<[], MessageID>({
170175
const maybeVd = AST.traverseUpGuard(node.parent, isVariableDeclaratorFromHookCall);
171176
if (O.isNone(maybeVd)) break;
172177
const vd = maybeVd.value;
173-
const calls = indirectSetStateCallsAsArgs.get(vd.init) ?? [];
174-
indirectSetStateCallsAsArgs.set(vd.init, [...calls, node]);
178+
const calls = indSetStateCallsInUseLayoutEffectArg0.get(vd.init) ?? [];
179+
indSetStateCallsInUseLayoutEffectArg0.set(vd.init, [...calls, node]);
175180
}
176181
// const [state, setState] = useState();
177182
// useLayoutEffect(setState);
178-
if (isUseEffectLikeCall(node.parent)) {
179-
const calls = indirectSetStateCallsAsArgs.get(node.parent) ?? [];
180-
indirectSetStateCallsAsSetups.set(node.parent, [...calls, node]);
183+
if (isUseLayoutEffectLikeCall(node.parent)) {
184+
const calls = indSetStateCallsInUseLayoutEffectArg0.get(node.parent) ?? [];
185+
indSetStateCallsInUseLayoutEffectSetup.set(node.parent, [...calls, node]);
181186
}
182187
break;
183188
}
@@ -193,13 +198,14 @@ export default createRule<[], MessageID>({
193198
case AST_NODE_TYPES.ArrowFunctionExpression:
194199
case AST_NODE_TYPES.FunctionDeclaration:
195200
case AST_NODE_TYPES.FunctionExpression:
196-
return indirectSetStateCalls.get(node) ?? [];
201+
return indSetStateCalls.get(node) ?? [];
197202
case AST_NODE_TYPES.CallExpression:
198-
return indirectSetStateCallsInHooks.get(node) ?? indirectSetStateCallsAsArgs.get(node) ?? [];
203+
return indSetStateCallsInUseMemoOrCallback.get(node) ?? indSetStateCallsInUseLayoutEffectArg0.get(node)
204+
?? [];
199205
}
200206
return [];
201207
};
202-
for (const [_, calls] of indirectSetStateCallsAsSetups) {
208+
for (const [_, calls] of indSetStateCallsInUseLayoutEffectSetup) {
203209
for (const call of calls) {
204210
context.report({
205211
messageId: "noDirectSetStateInUseLayoutEffect",
@@ -208,7 +214,7 @@ export default createRule<[], MessageID>({
208214
});
209215
}
210216
}
211-
for (const { callee } of indirectFunctionCalls) {
217+
for (const { callee } of indFunctionCalls) {
212218
if (!("name" in callee)) continue;
213219
const { name } = callee;
214220
const setStateCalls = getSetStateCalls(name, context.sourceCode.getScope(callee));

0 commit comments

Comments
 (0)