From eb58c3909aa19fb6ffbed27b9c9dba4aada3cb8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ari=20Perkki=C3=B6?= Date: Wed, 24 Mar 2021 18:45:27 +0200 Subject: [PATCH] react-hooks/exhaustive-deps: Handle optional chained methods as dependency (#20204) (#20247) --- .../ESLintRuleExhaustiveDeps-test.js | 30 +++++++++++++++++++ .../src/ExhaustiveDeps.js | 5 ++++ 2 files changed, 35 insertions(+) diff --git a/packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js b/packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js index 2a2786dca8850..430e78562491d 100644 --- a/packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js +++ b/packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js @@ -3629,6 +3629,36 @@ const tests = { }, ], }, + { + code: normalizeIndent` + function MyComponent(props) { + useEffect(() => {}, [props?.attribute.method()]); + } + `, + errors: [ + { + message: + 'React Hook useEffect has a complex expression in the dependency array. ' + + 'Extract it to a separate variable so it can be statically checked.', + suggestions: undefined, + }, + ], + }, + { + code: normalizeIndent` + function MyComponent(props) { + useEffect(() => {}, [props.method()]); + } + `, + errors: [ + { + message: + 'React Hook useEffect has a complex expression in the dependency array. ' + + 'Extract it to a separate variable so it can be statically checked.', + suggestions: undefined, + }, + ], + }, { code: normalizeIndent` function MyComponent() { diff --git a/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js b/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js index ee259b2d37cd6..2c76ca5991f76 100644 --- a/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js +++ b/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js @@ -1656,6 +1656,11 @@ function analyzePropertyChain(node, optionalChains) { return result; } else if (node.type === 'ChainExpression' && !node.computed) { const expression = node.expression; + + if (expression.type === 'CallExpression') { + throw new Error(`Unsupported node type: ${expression.type}`); + } + const object = analyzePropertyChain(expression.object, optionalChains); const property = analyzePropertyChain(expression.property, null); const result = `${object}.${property}`;