From 9daabc0bf97805be23f6131be4d84d063a3ff446 Mon Sep 17 00:00:00 2001 From: Marin Atanasov <8436925+tyxla@users.noreply.github.com> Date: Tue, 22 Oct 2024 23:07:10 +0300 Subject: [PATCH] `react-hooks/rules-of-hooks`: Add support for `do/while` loops (#28714) ## Summary Currently, `react-hooks/rules-of-hooks` does not support `do/while` loops - I've also reported this in https://github.com/facebook/react/issues/28713. This PR takes a stab at adding support for `do/while` by following the same logic we already have for detecting `while` loops. After this PR, any hooks called inside a `do/while` loop will be considered invalid. We're also adding some unit tests to confirm that the behavior is working as expected. Fixes #28713. ## How did you test this change? I've added unit tests that cover the case and verified that they pass by running: ``` yarn test packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js --watch ``` I've also verified that the rest of the tests continue to pass by running: ``` yarn test ``` and ``` yarn test --prod ``` --- .../__tests__/ESLintRulesOfHooks-test.js | 63 +++++++++++++++++++ .../src/RulesOfHooks.js | 2 +- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js b/packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js index a1e4c49e15..4376d01d82 100644 --- a/packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js +++ b/packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js @@ -755,6 +755,30 @@ const tests = { `, errors: [loopError('useHookInsideLoop')], }, + { + code: normalizeIndent` + // Invalid because it's dangerous and might not warn otherwise. + // This *must* be invalid. + function ComponentWithHookInsideLoop() { + do { + useHookInsideLoop(); + } while (cond); + } + `, + errors: [loopError('useHookInsideLoop')], + }, + { + code: normalizeIndent` + // Invalid because it's dangerous and might not warn otherwise. + // This *must* be invalid. + function ComponentWithHookInsideLoop() { + do { + foo(); + } while (useHookInsideLoop()); + } + `, + errors: [loopError('useHookInsideLoop')], + }, { code: normalizeIndent` // Invalid because it's dangerous and might not warn otherwise. @@ -853,6 +877,45 @@ const tests = { `, errors: [loopError('useHook1'), loopError('useHook2', true)], }, + { + code: normalizeIndent` + // Invalid because it's dangerous and might not warn otherwise. + // This *must* be invalid. + function useHookInLoops() { + do { + useHook1(); + if (a) return; + useHook2(); + } while (b); + + do { + useHook3(); + if (c) return; + useHook4(); + } while (d) + } + `, + errors: [ + loopError('useHook1'), + loopError('useHook2'), + loopError('useHook3'), + loopError('useHook4'), + ], + }, + { + code: normalizeIndent` + // Invalid because it's dangerous and might not warn otherwise. + // This *must* be invalid. + function useHookInLoops() { + do { + useHook1(); + if (a) continue; + useHook2(); + } while (b); + } + `, + errors: [loopError('useHook1'), loopError('useHook2', true)], + }, { code: normalizeIndent` // Invalid because it's dangerous and might not warn otherwise. diff --git a/packages/eslint-plugin-react-hooks/src/RulesOfHooks.js b/packages/eslint-plugin-react-hooks/src/RulesOfHooks.js index 97e72f01e4..0b89390898 100644 --- a/packages/eslint-plugin-react-hooks/src/RulesOfHooks.js +++ b/packages/eslint-plugin-react-hooks/src/RulesOfHooks.js @@ -295,7 +295,7 @@ export default { if (pathList.has(segment.id)) { const pathArray = Array.from(pathList); const cyclicSegments = pathArray.slice( - pathArray.indexOf(segment.id) + 1, + pathArray.indexOf(segment.id) - 1, ); for (const cyclicSegment of cyclicSegments) { cyclic.add(cyclicSegment);