From 7abe1acc96160733bbd7300b977f9cf7602a822b Mon Sep 17 00:00:00 2001
From: Afzal Sayed <14029371+afzalsayed96@users.noreply.github.com>
Date: Tue, 12 Apr 2022 00:15:15 +0530
Subject: [PATCH 1/4] Fix exhaustive deps for unstable vars
---
.../ESLintRuleExhaustiveDeps-test.js | 58 +++++++++++++++++++
.../src/ExhaustiveDeps.js | 9 ++-
2 files changed, 64 insertions(+), 3 deletions(-)
diff --git a/packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js b/packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js
index 4b6b3370e8b2..5c3c64c173fa 100644
--- a/packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js
+++ b/packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js
@@ -1095,6 +1095,22 @@ const tests = {
}
`,
},
+ {
+ code: normalizeIndent`
+ function Counter(unstableProp) {
+ let [count, setCount] = useState(0);
+ setCount = unstableProp
+ useEffect(() => {
+ let id = setInterval(() => {
+ setCount(c => c + 1);
+ }, 1000);
+ return () => clearInterval(id);
+ }, [setCount]);
+
+ return
{count}
;
+ }
+ `,
+ },
{
code: normalizeIndent`
function Counter() {
@@ -1581,6 +1597,48 @@ const tests = {
},
],
},
+ {
+ code: normalizeIndent`
+ function Counter(unstableProp) {
+ let [count, setCount] = useState(0);
+ setCount = unstableProp
+ useEffect(() => {
+ let id = setInterval(() => {
+ setCount(c => c + 1);
+ }, 1000);
+ return () => clearInterval(id);
+ }, []);
+
+ return {count}
;
+ }
+ `,
+ errors: [
+ {
+ message:
+ "React Hook useEffect has a missing dependency: 'setCount'. " +
+ 'Either include it or remove the dependency array.',
+ suggestions: [
+ {
+ desc: 'Update the dependencies array to be: [setCount]',
+ output: normalizeIndent`
+ function Counter(unstableProp) {
+ let [count, setCount] = useState(0);
+ setCount = unstableProp
+ useEffect(() => {
+ let id = setInterval(() => {
+ setCount(c => c + 1);
+ }, 1000);
+ return () => clearInterval(id);
+ }, [setCount]);
+
+ return {count}
;
+ }
+ `,
+ },
+ ],
+ },
+ ],
+ },
{
// Note: we *could* detect it's a primitive and never assigned
// even though it's not a constant -- but we currently don't.
diff --git a/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js b/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js
index 21d48141717c..87767648f18a 100644
--- a/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js
+++ b/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js
@@ -234,6 +234,9 @@ export default {
if (id.elements[1] === resolved.identifiers[0]) {
if (name === 'useState') {
const references = resolved.references;
+ // console.log(references);
+ if (references.filter(ref => ref.isWrite()).length > 1)
+ return false;
for (let i = 0; i < references.length; i++) {
setStateCallSites.set(
references[i].identifier,
@@ -321,7 +324,7 @@ export default {
pureScopes.has(ref.resolved.scope) &&
// Stable values are fine though,
// although we won't check functions deeper.
- !memoizedIsStablecKnownHookValue(ref.resolved)
+ !memoizedIsStableKnownHookValue(ref.resolved)
) {
return false;
}
@@ -332,7 +335,7 @@ export default {
}
// Remember such values. Avoid re-running extra checks on them.
- const memoizedIsStablecKnownHookValue = memoizeWithWeakMap(
+ const memoizedIsStableKnownHookValue = memoizeWithWeakMap(
isStableKnownHookValue,
stableKnownValueCache,
);
@@ -435,7 +438,7 @@ export default {
if (!dependencies.has(dependency)) {
const resolved = reference.resolved;
const isStable =
- memoizedIsStablecKnownHookValue(resolved) ||
+ memoizedIsStableKnownHookValue(resolved) ||
memoizedIsFunctionWithoutCapturedValues(resolved);
dependencies.set(dependency, {
isStable,
From bcf5beaf5f19f7fa2945be30fbc0d7a1dfa73185 Mon Sep 17 00:00:00 2001
From: Afzal Sayed <14029371+afzalsayed96@users.noreply.github.com>
Date: Tue, 12 Apr 2022 00:34:32 +0530
Subject: [PATCH 2/4] Fix formatting
---
packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js b/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js
index 87767648f18a..ab5f84404684 100644
--- a/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js
+++ b/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js
@@ -234,9 +234,9 @@ export default {
if (id.elements[1] === resolved.identifiers[0]) {
if (name === 'useState') {
const references = resolved.references;
- // console.log(references);
- if (references.filter(ref => ref.isWrite()).length > 1)
+ if (references.filter(ref => ref.isWrite()).length > 1) {
return false;
+ }
for (let i = 0; i < references.length; i++) {
setStateCallSites.set(
references[i].identifier,
From ef66085f07402b976feae9b7586cd1bcbe9bd2b2 Mon Sep 17 00:00:00 2001
From: Afzal Sayed <14029371+afzalsayed96@users.noreply.github.com>
Date: Tue, 12 Apr 2022 01:00:57 +0530
Subject: [PATCH 3/4] Optimise iterations
---
.../eslint-plugin-react-hooks/src/ExhaustiveDeps.js | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js b/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js
index ab5f84404684..cf8a6d8af014 100644
--- a/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js
+++ b/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js
@@ -234,10 +234,14 @@ export default {
if (id.elements[1] === resolved.identifiers[0]) {
if (name === 'useState') {
const references = resolved.references;
- if (references.filter(ref => ref.isWrite()).length > 1) {
- return false;
- }
+ let writeCount = 0
for (let i = 0; i < references.length; i++) {
+ if (references[i].isWrite()) {
+ writeCount++
+ }
+ if (writeCount > 1) {
+ return false;
+ }
setStateCallSites.set(
references[i].identifier,
id.elements[0],
From 9152b75a8c8cd89a3890bb5e483cd6eb312b0617 Mon Sep 17 00:00:00 2001
From: Afzal Sayed <14029371+afzalsayed96@users.noreply.github.com>
Date: Tue, 12 Apr 2022 01:36:45 +0530
Subject: [PATCH 4/4] Fix linting
---
packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js b/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js
index cf8a6d8af014..26d9688ac17c 100644
--- a/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js
+++ b/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js
@@ -234,10 +234,10 @@ export default {
if (id.elements[1] === resolved.identifiers[0]) {
if (name === 'useState') {
const references = resolved.references;
- let writeCount = 0
+ let writeCount = 0;
for (let i = 0; i < references.length; i++) {
if (references[i].isWrite()) {
- writeCount++
+ writeCount++;
}
if (writeCount > 1) {
return false;