[eslint] Wording tweaks (#15078)
* [eslint] Wording tweaks I think these are a little clearer. * fix tests
This commit is contained in:
parent
9d77a317bf
commit
1204c78977
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"root": true,
|
"root": true,
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": 6,
|
"ecmaVersion": 8,
|
||||||
"sourceType": "module",
|
"sourceType": "module",
|
||||||
"ecmaFeatures": {
|
"ecmaFeatures": {
|
||||||
"jsx": true
|
"jsx": true
|
||||||
|
|
|
@ -1060,12 +1060,10 @@ const tests = {
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
errors: [
|
errors: [
|
||||||
"React Hook useMemo doesn't serve any purpose without a dependency array. " +
|
'React Hook useMemo does nothing when called with only one argument. ' +
|
||||||
'To enable this optimization, pass an array of values used by the inner ' +
|
'Did you forget to pass an array of dependencies?',
|
||||||
'function as the second argument to useMemo.',
|
'React Hook useCallback does nothing when called with only one argument. ' +
|
||||||
"React Hook useCallback doesn't serve any purpose without a dependency array. " +
|
'Did you forget to pass an array of dependencies?',
|
||||||
'To enable this optimization, pass an array of values used by the inner ' +
|
|
||||||
'function as the second argument to useCallback.',
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1260,7 +1258,7 @@ const tests = {
|
||||||
"React Hook useCallback has a missing dependency: 'local2'. " +
|
"React Hook useCallback has a missing dependency: 'local2'. " +
|
||||||
'Either include it or remove the dependency array. ' +
|
'Either include it or remove the dependency array. ' +
|
||||||
"Outer scope values like 'local1' aren't valid dependencies " +
|
"Outer scope values like 'local1' aren't valid dependencies " +
|
||||||
"because their mutation doesn't re-render the component.",
|
"because mutating them doesn't re-render the component.",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1326,7 +1324,7 @@ const tests = {
|
||||||
"React Hook useCallback has an unnecessary dependency: 'window'. " +
|
"React Hook useCallback has an unnecessary dependency: 'window'. " +
|
||||||
'Either exclude it or remove the dependency array. ' +
|
'Either exclude it or remove the dependency array. ' +
|
||||||
"Outer scope values like 'window' aren't valid dependencies " +
|
"Outer scope values like 'window' aren't valid dependencies " +
|
||||||
"because their mutation doesn't re-render the component.",
|
"because mutating them doesn't re-render the component.",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1395,6 +1393,24 @@ const tests = {
|
||||||
'Either include it or remove the dependency array.',
|
'Either include it or remove the dependency array.',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
code: `
|
||||||
|
function MyComponent() {
|
||||||
|
useEffect(() => {}, ['foo']);
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
// TODO: we could autofix this.
|
||||||
|
output: `
|
||||||
|
function MyComponent() {
|
||||||
|
useEffect(() => {}, ['foo']);
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
errors: [
|
||||||
|
// Don't assume user meant `foo` because it's not used in the effect.
|
||||||
|
"The 'foo' literal is not a valid dependency because it never changes. " +
|
||||||
|
'You can safely remove it.',
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
code: `
|
code: `
|
||||||
function MyComponent({ foo, bar, baz }) {
|
function MyComponent({ foo, bar, baz }) {
|
||||||
|
@ -1413,9 +1429,9 @@ const tests = {
|
||||||
errors: [
|
errors: [
|
||||||
"React Hook useEffect has missing dependencies: 'bar', 'baz', and 'foo'. " +
|
"React Hook useEffect has missing dependencies: 'bar', 'baz', and 'foo'. " +
|
||||||
'Either include them or remove the dependency array.',
|
'Either include them or remove the dependency array.',
|
||||||
"The 'foo' string literal is not a valid dependency because it never changes. " +
|
"The 'foo' literal is not a valid dependency because it never changes. " +
|
||||||
'Did you mean to include foo in the array instead?',
|
'Did you mean to include foo in the array instead?',
|
||||||
"The 'bar' string literal is not a valid dependency because it never changes. " +
|
"The 'bar' literal is not a valid dependency because it never changes. " +
|
||||||
'Did you mean to include bar in the array instead?',
|
'Did you mean to include bar in the array instead?',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -1437,9 +1453,9 @@ const tests = {
|
||||||
errors: [
|
errors: [
|
||||||
"React Hook useEffect has missing dependencies: 'bar', 'baz', and 'foo'. " +
|
"React Hook useEffect has missing dependencies: 'bar', 'baz', and 'foo'. " +
|
||||||
'Either include them or remove the dependency array.',
|
'Either include them or remove the dependency array.',
|
||||||
"The '42' literal is not a valid dependency because it never changes. You can safely remove it.",
|
'The 42 literal is not a valid dependency because it never changes. You can safely remove it.',
|
||||||
"The 'false' literal is not a valid dependency because it never changes. You can safely remove it.",
|
'The false literal is not a valid dependency because it never changes. You can safely remove it.',
|
||||||
"The 'null' literal is not a valid dependency because it never changes. You can safely remove it.",
|
'The null literal is not a valid dependency because it never changes. You can safely remove it.',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1456,8 +1472,8 @@ const tests = {
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
errors: [
|
errors: [
|
||||||
'React Hook useEffect has a second argument which is not an array ' +
|
'React Hook useEffect was passed a dependency list that is not an ' +
|
||||||
"literal. This means we can't statically verify whether you've " +
|
"array literal. This means we can't statically verify whether you've " +
|
||||||
'passed the correct dependencies.',
|
'passed the correct dependencies.',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -1482,8 +1498,8 @@ const tests = {
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
errors: [
|
errors: [
|
||||||
'React Hook useEffect has a second argument which is not an array ' +
|
'React Hook useEffect was passed a dependency list that is not an ' +
|
||||||
"literal. This means we can't statically verify whether you've " +
|
"array literal. This means we can't statically verify whether you've " +
|
||||||
'passed the correct dependencies.',
|
'passed the correct dependencies.',
|
||||||
"React Hook useEffect has a missing dependency: 'local'. " +
|
"React Hook useEffect has a missing dependency: 'local'. " +
|
||||||
'Either include it or remove the dependency array.',
|
'Either include it or remove the dependency array.',
|
||||||
|
@ -2327,8 +2343,8 @@ const tests = {
|
||||||
errors: [
|
errors: [
|
||||||
"React Hook useEffect has a missing dependency: 'state'. " +
|
"React Hook useEffect has a missing dependency: 'state'. " +
|
||||||
'Either include it or remove the dependency array. ' +
|
'Either include it or remove the dependency array. ' +
|
||||||
`You can also write 'setState(s => ...)' ` +
|
`You can also do a functional update 'setState(s => ...)' ` +
|
||||||
`if you only use 'state' for the 'setState' call.`,
|
`if you only need 'state' in the 'setState' call.`,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2358,8 +2374,8 @@ const tests = {
|
||||||
errors: [
|
errors: [
|
||||||
"React Hook useEffect has a missing dependency: 'state'. " +
|
"React Hook useEffect has a missing dependency: 'state'. " +
|
||||||
'Either include it or remove the dependency array. ' +
|
'Either include it or remove the dependency array. ' +
|
||||||
`You can also write 'setState(s => ...)' ` +
|
`You can also do a functional update 'setState(s => ...)' ` +
|
||||||
`if you only use 'state' for the 'setState' call.`,
|
`if you only need 'state' in the 'setState' call.`,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2421,7 +2437,7 @@ const tests = {
|
||||||
"React Hook useEffect has unnecessary dependencies: 'ref1.current' and 'ref2.current'. " +
|
"React Hook useEffect has unnecessary dependencies: 'ref1.current' and 'ref2.current'. " +
|
||||||
'Either exclude them or remove the dependency array. ' +
|
'Either exclude them or remove the dependency array. ' +
|
||||||
"Mutable values like 'ref1.current' aren't valid dependencies " +
|
"Mutable values like 'ref1.current' aren't valid dependencies " +
|
||||||
"because their mutation doesn't re-render the component.",
|
"because mutating them doesn't re-render the component.",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2445,7 +2461,7 @@ const tests = {
|
||||||
"React Hook useEffect has an unnecessary dependency: 'ref.current'. " +
|
"React Hook useEffect has an unnecessary dependency: 'ref.current'. " +
|
||||||
'Either exclude it or remove the dependency array. ' +
|
'Either exclude it or remove the dependency array. ' +
|
||||||
"Mutable values like 'ref.current' aren't valid dependencies " +
|
"Mutable values like 'ref.current' aren't valid dependencies " +
|
||||||
"because their mutation doesn't re-render the component.",
|
"because mutating them doesn't re-render the component.",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2473,7 +2489,7 @@ const tests = {
|
||||||
"React Hook useEffect has unnecessary dependencies: 'ref1.current' and 'ref2.current'. " +
|
"React Hook useEffect has unnecessary dependencies: 'ref1.current' and 'ref2.current'. " +
|
||||||
'Either exclude them or remove the dependency array. ' +
|
'Either exclude them or remove the dependency array. ' +
|
||||||
"Mutable values like 'ref1.current' aren't valid dependencies " +
|
"Mutable values like 'ref1.current' aren't valid dependencies " +
|
||||||
"because their mutation doesn't re-render the component.",
|
"because mutating them doesn't re-render the component.",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2501,7 +2517,7 @@ const tests = {
|
||||||
"React Hook useCallback has unnecessary dependencies: 'activeTab', 'ref1.current', and 'ref2.current'. " +
|
"React Hook useCallback has unnecessary dependencies: 'activeTab', 'ref1.current', and 'ref2.current'. " +
|
||||||
'Either exclude them or remove the dependency array. ' +
|
'Either exclude them or remove the dependency array. ' +
|
||||||
"Mutable values like 'ref1.current' aren't valid dependencies " +
|
"Mutable values like 'ref1.current' aren't valid dependencies " +
|
||||||
"because their mutation doesn't re-render the component.",
|
"because mutating them doesn't re-render the component.",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2525,7 +2541,7 @@ const tests = {
|
||||||
"React Hook useEffect has an unnecessary dependency: 'ref.current'. " +
|
"React Hook useEffect has an unnecessary dependency: 'ref.current'. " +
|
||||||
'Either exclude it or remove the dependency array. ' +
|
'Either exclude it or remove the dependency array. ' +
|
||||||
"Mutable values like 'ref.current' aren't valid dependencies " +
|
"Mutable values like 'ref.current' aren't valid dependencies " +
|
||||||
"because their mutation doesn't re-render the component.",
|
"because mutating them doesn't re-render the component.",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2574,9 +2590,10 @@ const tests = {
|
||||||
errors: [
|
errors: [
|
||||||
"React Hook useEffect has a missing dependency: 'props'. " +
|
"React Hook useEffect has a missing dependency: 'props'. " +
|
||||||
'Either include it or remove the dependency array. ' +
|
'Either include it or remove the dependency array. ' +
|
||||||
`However, the preferred fix is to destructure the 'props' ` +
|
`However, 'props' will change when *any* prop changes, so the ` +
|
||||||
`object outside of the useEffect call and refer to specific ` +
|
`preferred fix is to destructure the 'props' object outside ` +
|
||||||
`props directly by their names.`,
|
`of the useEffect call and refer to those specific ` +
|
||||||
|
`props inside useEffect.`,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2607,9 +2624,10 @@ const tests = {
|
||||||
errors: [
|
errors: [
|
||||||
"React Hook useEffect has a missing dependency: 'props'. " +
|
"React Hook useEffect has a missing dependency: 'props'. " +
|
||||||
'Either include it or remove the dependency array. ' +
|
'Either include it or remove the dependency array. ' +
|
||||||
`However, the preferred fix is to destructure the 'props' ` +
|
`However, 'props' will change when *any* prop changes, so the ` +
|
||||||
`object outside of the useEffect call and refer to specific ` +
|
`preferred fix is to destructure the 'props' object outside ` +
|
||||||
`props directly by their names.`,
|
`of the useEffect call and refer to those specific ` +
|
||||||
|
`props inside useEffect.`,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2660,9 +2678,10 @@ const tests = {
|
||||||
errors: [
|
errors: [
|
||||||
"React Hook useEffect has a missing dependency: 'props'. " +
|
"React Hook useEffect has a missing dependency: 'props'. " +
|
||||||
'Either include it or remove the dependency array. ' +
|
'Either include it or remove the dependency array. ' +
|
||||||
`However, the preferred fix is to destructure the 'props' ` +
|
`However, 'props' will change when *any* prop changes, so the ` +
|
||||||
`object outside of the useEffect call and refer to specific ` +
|
`preferred fix is to destructure the 'props' object outside ` +
|
||||||
`props directly by their names.`,
|
`of the useEffect call and refer to those specific ` +
|
||||||
|
`props inside useEffect.`,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2689,9 +2708,10 @@ const tests = {
|
||||||
errors: [
|
errors: [
|
||||||
"React Hook useEffect has a missing dependency: 'props'. " +
|
"React Hook useEffect has a missing dependency: 'props'. " +
|
||||||
'Either include it or remove the dependency array. ' +
|
'Either include it or remove the dependency array. ' +
|
||||||
`However, the preferred fix is to destructure the 'props' ` +
|
`However, 'props' will change when *any* prop changes, so the ` +
|
||||||
`object outside of the useEffect call and refer to specific ` +
|
`preferred fix is to destructure the 'props' object outside ` +
|
||||||
`props directly by their names.`,
|
`of the useEffect call and refer to those specific ` +
|
||||||
|
`props inside useEffect.`,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2718,9 +2738,10 @@ const tests = {
|
||||||
errors: [
|
errors: [
|
||||||
"React Hook useEffect has missing dependencies: 'props' and 'skillsCount'. " +
|
"React Hook useEffect has missing dependencies: 'props' and 'skillsCount'. " +
|
||||||
'Either include them or remove the dependency array. ' +
|
'Either include them or remove the dependency array. ' +
|
||||||
`However, the preferred fix is to destructure the 'props' ` +
|
`However, 'props' will change when *any* prop changes, so the ` +
|
||||||
`object outside of the useEffect call and refer to specific ` +
|
`preferred fix is to destructure the 'props' object outside ` +
|
||||||
`props directly by their names.`,
|
`of the useEffect call and refer to those specific ` +
|
||||||
|
`props inside useEffect.`,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2819,29 +2840,25 @@ const tests = {
|
||||||
`,
|
`,
|
||||||
errors: [
|
errors: [
|
||||||
// value2
|
// value2
|
||||||
`Assignments to the 'value2' variable from inside a React useEffect Hook ` +
|
`Assignments to the 'value2' variable from inside React Hook useEffect ` +
|
||||||
`will not persist between re-renders. ` +
|
`will be lost after each render. To preserve the value over time, ` +
|
||||||
`If it's only needed by this Hook, move the variable inside it. ` +
|
`store it in a useRef Hook and keep the mutable value in the '.current' property. ` +
|
||||||
`Alternatively, declare a ref with the useRef Hook, ` +
|
`Otherwise, you can move this variable directly inside useEffect.`,
|
||||||
`and keep the mutable value in its 'current' property.`,
|
|
||||||
// value
|
// value
|
||||||
`Assignments to the 'value' variable from inside a React useEffect Hook ` +
|
`Assignments to the 'value' variable from inside React Hook useEffect ` +
|
||||||
`will not persist between re-renders. ` +
|
`will be lost after each render. To preserve the value over time, ` +
|
||||||
`If it's only needed by this Hook, move the variable inside it. ` +
|
`store it in a useRef Hook and keep the mutable value in the '.current' property. ` +
|
||||||
`Alternatively, declare a ref with the useRef Hook, ` +
|
`Otherwise, you can move this variable directly inside useEffect.`,
|
||||||
`and keep the mutable value in its 'current' property.`,
|
|
||||||
// value4
|
// value4
|
||||||
`Assignments to the 'value4' variable from inside a React useEffect Hook ` +
|
`Assignments to the 'value4' variable from inside React Hook useEffect ` +
|
||||||
`will not persist between re-renders. ` +
|
`will be lost after each render. To preserve the value over time, ` +
|
||||||
`If it's only needed by this Hook, move the variable inside it. ` +
|
`store it in a useRef Hook and keep the mutable value in the '.current' property. ` +
|
||||||
`Alternatively, declare a ref with the useRef Hook, ` +
|
`Otherwise, you can move this variable directly inside useEffect.`,
|
||||||
`and keep the mutable value in its 'current' property.`,
|
|
||||||
// asyncValue
|
// asyncValue
|
||||||
`Assignments to the 'asyncValue' variable from inside a React useEffect Hook ` +
|
`Assignments to the 'asyncValue' variable from inside React Hook useEffect ` +
|
||||||
`will not persist between re-renders. ` +
|
`will be lost after each render. To preserve the value over time, ` +
|
||||||
`If it's only needed by this Hook, move the variable inside it. ` +
|
`store it in a useRef Hook and keep the mutable value in the '.current' property. ` +
|
||||||
`Alternatively, declare a ref with the useRef Hook, ` +
|
`Otherwise, you can move this variable directly inside useEffect.`,
|
||||||
`and keep the mutable value in its 'current' property.`,
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2886,23 +2903,20 @@ const tests = {
|
||||||
`,
|
`,
|
||||||
errors: [
|
errors: [
|
||||||
// value
|
// value
|
||||||
`Assignments to the 'value' variable from inside a React useEffect Hook ` +
|
`Assignments to the 'value' variable from inside React Hook useEffect ` +
|
||||||
`will not persist between re-renders. ` +
|
`will be lost after each render. To preserve the value over time, ` +
|
||||||
`If it's only needed by this Hook, move the variable inside it. ` +
|
`store it in a useRef Hook and keep the mutable value in the '.current' property. ` +
|
||||||
`Alternatively, declare a ref with the useRef Hook, ` +
|
`Otherwise, you can move this variable directly inside useEffect.`,
|
||||||
`and keep the mutable value in its 'current' property.`,
|
|
||||||
// value2
|
// value2
|
||||||
`Assignments to the 'value2' variable from inside a React useEffect Hook ` +
|
`Assignments to the 'value2' variable from inside React Hook useEffect ` +
|
||||||
`will not persist between re-renders. ` +
|
`will be lost after each render. To preserve the value over time, ` +
|
||||||
`If it's only needed by this Hook, move the variable inside it. ` +
|
`store it in a useRef Hook and keep the mutable value in the '.current' property. ` +
|
||||||
`Alternatively, declare a ref with the useRef Hook, ` +
|
`Otherwise, you can move this variable directly inside useEffect.`,
|
||||||
`and keep the mutable value in its 'current' property.`,
|
|
||||||
// asyncValue
|
// asyncValue
|
||||||
`Assignments to the 'asyncValue' variable from inside a React useEffect Hook ` +
|
`Assignments to the 'asyncValue' variable from inside React Hook useEffect ` +
|
||||||
`will not persist between re-renders. ` +
|
`will be lost after each render. To preserve the value over time, ` +
|
||||||
`If it's only needed by this Hook, move the variable inside it. ` +
|
`store it in a useRef Hook and keep the mutable value in the '.current' property. ` +
|
||||||
`Alternatively, declare a ref with the useRef Hook, ` +
|
`Otherwise, you can move this variable directly inside useEffect.`,
|
||||||
`and keep the mutable value in its 'current' property.`,
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2929,11 +2943,10 @@ const tests = {
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
errors: [
|
errors: [
|
||||||
`Accessing 'myRef.current' during the effect cleanup ` +
|
`The ref value 'myRef.current' will likely have changed by the time ` +
|
||||||
`will likely read a different ref value because by this time React ` +
|
`this effect cleanup function runs. If this ref points to a node ` +
|
||||||
`has already updated the ref. If this ref is managed by React, store ` +
|
`rendered by React, copy 'myRef.current' to a variable inside the effect, ` +
|
||||||
`'myRef.current' in a variable inside ` +
|
`and use that variable in the cleanup function.`,
|
||||||
`the effect itself and refer to that variable from the cleanup function.`,
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2956,11 +2969,10 @@ const tests = {
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
errors: [
|
errors: [
|
||||||
`Accessing 'myRef.current' during the effect cleanup ` +
|
`The ref value 'myRef.current' will likely have changed by the time ` +
|
||||||
`will likely read a different ref value because by this time React ` +
|
`this effect cleanup function runs. If this ref points to a node ` +
|
||||||
`has already updated the ref. If this ref is managed by React, store ` +
|
`rendered by React, copy 'myRef.current' to a variable inside the effect, ` +
|
||||||
`'myRef.current' in a variable inside ` +
|
`and use that variable in the cleanup function.`,
|
||||||
`the effect itself and refer to that variable from the cleanup function.`,
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2995,11 +3007,10 @@ const tests = {
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
errors: [
|
errors: [
|
||||||
`Accessing 'myRef.current' during the effect cleanup ` +
|
`The ref value 'myRef.current' will likely have changed by the time ` +
|
||||||
`will likely read a different ref value because by this time React ` +
|
`this effect cleanup function runs. If this ref points to a node ` +
|
||||||
`has already updated the ref. If this ref is managed by React, store ` +
|
`rendered by React, copy 'myRef.current' to a variable inside the effect, ` +
|
||||||
`'myRef.current' in a variable inside ` +
|
`and use that variable in the cleanup function.`,
|
||||||
`the effect itself and refer to that variable from the cleanup function.`,
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -3034,11 +3045,10 @@ const tests = {
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
errors: [
|
errors: [
|
||||||
`Accessing 'myRef.current' during the effect cleanup ` +
|
`The ref value 'myRef.current' will likely have changed by the time ` +
|
||||||
`will likely read a different ref value because by this time React ` +
|
`this effect cleanup function runs. If this ref points to a node ` +
|
||||||
`has already updated the ref. If this ref is managed by React, store ` +
|
`rendered by React, copy 'myRef.current' to a variable inside the effect, ` +
|
||||||
`'myRef.current' in a variable inside ` +
|
`and use that variable in the cleanup function.`,
|
||||||
`the effect itself and refer to that variable from the cleanup function.`,
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -3088,7 +3098,7 @@ const tests = {
|
||||||
"React Hook useEffect has an unnecessary dependency: 'window'. " +
|
"React Hook useEffect has an unnecessary dependency: 'window'. " +
|
||||||
'Either exclude it or remove the dependency array. ' +
|
'Either exclude it or remove the dependency array. ' +
|
||||||
"Outer scope values like 'window' aren't valid dependencies " +
|
"Outer scope values like 'window' aren't valid dependencies " +
|
||||||
"because their mutation doesn't re-render the component.",
|
"because mutating them doesn't re-render the component.",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -3114,7 +3124,7 @@ const tests = {
|
||||||
"React Hook useEffect has an unnecessary dependency: 'MutableStore.hello'. " +
|
"React Hook useEffect has an unnecessary dependency: 'MutableStore.hello'. " +
|
||||||
'Either exclude it or remove the dependency array. ' +
|
'Either exclude it or remove the dependency array. ' +
|
||||||
"Outer scope values like 'MutableStore.hello' aren't valid dependencies " +
|
"Outer scope values like 'MutableStore.hello' aren't valid dependencies " +
|
||||||
"because their mutation doesn't re-render the component.",
|
"because mutating them doesn't re-render the component.",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -3151,7 +3161,7 @@ const tests = {
|
||||||
"'MutableStore.hello.world', 'global.stuff', and 'z'. " +
|
"'MutableStore.hello.world', 'global.stuff', and 'z'. " +
|
||||||
'Either exclude them or remove the dependency array. ' +
|
'Either exclude them or remove the dependency array. ' +
|
||||||
"Outer scope values like 'MutableStore.hello.world' aren't valid dependencies " +
|
"Outer scope values like 'MutableStore.hello.world' aren't valid dependencies " +
|
||||||
"because their mutation doesn't re-render the component.",
|
"because mutating them doesn't re-render the component.",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -3190,7 +3200,7 @@ const tests = {
|
||||||
"'MutableStore.hello.world', 'global.stuff', and 'z'. " +
|
"'MutableStore.hello.world', 'global.stuff', and 'z'. " +
|
||||||
'Either exclude them or remove the dependency array. ' +
|
'Either exclude them or remove the dependency array. ' +
|
||||||
"Outer scope values like 'MutableStore.hello.world' aren't valid dependencies " +
|
"Outer scope values like 'MutableStore.hello.world' aren't valid dependencies " +
|
||||||
"because their mutation doesn't re-render the component.",
|
"because mutating them doesn't re-render the component.",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -3227,7 +3237,7 @@ const tests = {
|
||||||
"'MutableStore.hello.world', 'global.stuff', 'props.foo', 'x', 'y', and 'z'. " +
|
"'MutableStore.hello.world', 'global.stuff', 'props.foo', 'x', 'y', and 'z'. " +
|
||||||
'Either exclude them or remove the dependency array. ' +
|
'Either exclude them or remove the dependency array. ' +
|
||||||
"Outer scope values like 'MutableStore.hello.world' aren't valid dependencies " +
|
"Outer scope values like 'MutableStore.hello.world' aren't valid dependencies " +
|
||||||
"because their mutation doesn't re-render the component.",
|
"because mutating them doesn't re-render the component.",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -3956,8 +3966,8 @@ const tests = {
|
||||||
errors: [
|
errors: [
|
||||||
"React Hook useEffect has a missing dependency: 'count'. " +
|
"React Hook useEffect has a missing dependency: 'count'. " +
|
||||||
'Either include it or remove the dependency array. ' +
|
'Either include it or remove the dependency array. ' +
|
||||||
`You can also write 'setCount(c => ...)' if you ` +
|
`You can also do a functional update 'setCount(c => ...)' if you ` +
|
||||||
`only use 'count' for the 'setCount' call.`,
|
`only need 'count' in the 'setCount' call.`,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -3994,8 +4004,8 @@ const tests = {
|
||||||
errors: [
|
errors: [
|
||||||
"React Hook useEffect has missing dependencies: 'count' and 'increment'. " +
|
"React Hook useEffect has missing dependencies: 'count' and 'increment'. " +
|
||||||
'Either include them or remove the dependency array. ' +
|
'Either include them or remove the dependency array. ' +
|
||||||
`You can also write 'setCount(c => ...)' if you ` +
|
`You can also do a functional update 'setCount(c => ...)' if you ` +
|
||||||
`only use 'count' for the 'setCount' call.`,
|
`only need 'count' in the 'setCount' call.`,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -4196,8 +4206,8 @@ const tests = {
|
||||||
errors: [
|
errors: [
|
||||||
"React Hook useEffect has a missing dependency: 'increment'. " +
|
"React Hook useEffect has a missing dependency: 'increment'. " +
|
||||||
'Either include it or remove the dependency array. ' +
|
'Either include it or remove the dependency array. ' +
|
||||||
'You can also replace useState with an inline useReducer ' +
|
`If 'setCount' needs the current value of 'increment', ` +
|
||||||
`if 'setCount' needs the current value of 'increment'.`,
|
`you can also switch to useReducer instead of useState and read 'increment' in the reducer.`,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -4292,7 +4302,7 @@ const tests = {
|
||||||
errors: [
|
errors: [
|
||||||
`React Hook useEffect has a missing dependency: 'fetchPodcasts'. ` +
|
`React Hook useEffect has a missing dependency: 'fetchPodcasts'. ` +
|
||||||
`Either include it or remove the dependency array. ` +
|
`Either include it or remove the dependency array. ` +
|
||||||
`If specifying 'fetchPodcasts' makes the dependencies change too often, ` +
|
`If 'fetchPodcasts' changes too often, ` +
|
||||||
`find the parent component that defines it and wrap that definition in useCallback.`,
|
`find the parent component that defines it and wrap that definition in useCallback.`,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -4316,7 +4326,7 @@ const tests = {
|
||||||
errors: [
|
errors: [
|
||||||
`React Hook useEffect has a missing dependency: 'fetchPodcasts'. ` +
|
`React Hook useEffect has a missing dependency: 'fetchPodcasts'. ` +
|
||||||
`Either include it or remove the dependency array. ` +
|
`Either include it or remove the dependency array. ` +
|
||||||
`If specifying 'fetchPodcasts' makes the dependencies change too often, ` +
|
`If 'fetchPodcasts' changes too often, ` +
|
||||||
`find the parent component that defines it and wrap that definition in useCallback.`,
|
`find the parent component that defines it and wrap that definition in useCallback.`,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -4348,7 +4358,7 @@ const tests = {
|
||||||
errors: [
|
errors: [
|
||||||
`React Hook useEffect has missing dependencies: 'fetchPodcasts' and 'fetchPodcasts2'. ` +
|
`React Hook useEffect has missing dependencies: 'fetchPodcasts' and 'fetchPodcasts2'. ` +
|
||||||
`Either include them or remove the dependency array. ` +
|
`Either include them or remove the dependency array. ` +
|
||||||
`If specifying 'fetchPodcasts' makes the dependencies change too often, ` +
|
`If 'fetchPodcasts' changes too often, ` +
|
||||||
`find the parent component that defines it and wrap that definition in useCallback.`,
|
`find the parent component that defines it and wrap that definition in useCallback.`,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -4374,7 +4384,7 @@ const tests = {
|
||||||
errors: [
|
errors: [
|
||||||
`React Hook useEffect has a missing dependency: 'fetchPodcasts'. ` +
|
`React Hook useEffect has a missing dependency: 'fetchPodcasts'. ` +
|
||||||
`Either include it or remove the dependency array. ` +
|
`Either include it or remove the dependency array. ` +
|
||||||
`If specifying 'fetchPodcasts' makes the dependencies change too often, ` +
|
`If 'fetchPodcasts' changes too often, ` +
|
||||||
`find the parent component that defines it and wrap that definition in useCallback.`,
|
`find the parent component that defines it and wrap that definition in useCallback.`,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -4426,7 +4436,7 @@ const tests = {
|
||||||
` }\n` +
|
` }\n` +
|
||||||
`\n` +
|
`\n` +
|
||||||
` return () => { ignore = true; };\n` +
|
` return () => { ignore = true; };\n` +
|
||||||
`}, []);\n` +
|
`}, ...);\n` +
|
||||||
`\n` +
|
`\n` +
|
||||||
`This lets you handle multiple requests without bugs.`,
|
`This lets you handle multiple requests without bugs.`,
|
||||||
],
|
],
|
||||||
|
|
|
@ -94,13 +94,13 @@ export default {
|
||||||
reactiveHookName === 'useMemo' ||
|
reactiveHookName === 'useMemo' ||
|
||||||
reactiveHookName === 'useCallback'
|
reactiveHookName === 'useCallback'
|
||||||
) {
|
) {
|
||||||
|
// TODO: Can this have an autofix?
|
||||||
context.report({
|
context.report({
|
||||||
node: node.parent.callee,
|
node: node.parent.callee,
|
||||||
message:
|
message:
|
||||||
`React Hook ${reactiveHookName} doesn't serve any purpose ` +
|
`React Hook ${reactiveHookName} does nothing when called with ` +
|
||||||
`without a dependency array. To enable ` +
|
`only one argument. Did you forget to pass an array of ` +
|
||||||
`this optimization, pass an array of values used by the ` +
|
`dependencies?`,
|
||||||
`inner function as the second argument to ${reactiveHookName}.`,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -122,7 +122,7 @@ export default {
|
||||||
` }\n` +
|
` }\n` +
|
||||||
`\n` +
|
`\n` +
|
||||||
` return () => { ignore = true; };\n` +
|
` return () => { ignore = true; };\n` +
|
||||||
`}, []);\n` +
|
`}, ...);\n` +
|
||||||
`\n` +
|
`\n` +
|
||||||
`This lets you handle multiple requests without bugs.`,
|
`This lets you handle multiple requests without bugs.`,
|
||||||
});
|
});
|
||||||
|
@ -453,11 +453,11 @@ export default {
|
||||||
context.report({
|
context.report({
|
||||||
node: dependencyNode.parent.property,
|
node: dependencyNode.parent.property,
|
||||||
message:
|
message:
|
||||||
`Accessing '${dependency}.current' during the effect cleanup ` +
|
`The ref value '${dependency}.current' will likely have ` +
|
||||||
`will likely read a different ref value because by this time React ` +
|
`changed by the time this effect cleanup function runs. If ` +
|
||||||
`has already updated the ref. If this ref is managed by React, store ` +
|
`this ref points to a node rendered by React, copy ` +
|
||||||
`'${dependency}.current' in a variable inside ` +
|
`'${dependency}.current' to a variable inside the effect, and ` +
|
||||||
`the effect itself and refer to that variable from the cleanup function.`,
|
`use that variable in the cleanup function.`,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -471,9 +471,10 @@ export default {
|
||||||
context.report({
|
context.report({
|
||||||
node: declaredDependenciesNode,
|
node: declaredDependenciesNode,
|
||||||
message:
|
message:
|
||||||
`React Hook ${context.getSource(reactiveHook)} has a second ` +
|
`React Hook ${context.getSource(reactiveHook)} was passed a ` +
|
||||||
"argument which is not an array literal. This means we can't " +
|
'dependency list that is not an array literal. This means we ' +
|
||||||
"statically verify whether you've passed the correct dependencies.",
|
"can't statically verify whether you've passed the correct " +
|
||||||
|
'dependencies.',
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
declaredDependenciesNode.elements.forEach(declaredDependencyNode => {
|
declaredDependenciesNode.elements.forEach(declaredDependencyNode => {
|
||||||
|
@ -501,15 +502,15 @@ export default {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (/Unsupported node type/.test(error.message)) {
|
if (/Unsupported node type/.test(error.message)) {
|
||||||
if (declaredDependencyNode.type === 'Literal') {
|
if (declaredDependencyNode.type === 'Literal') {
|
||||||
if (typeof declaredDependencyNode.value === 'string') {
|
if (dependencies.has(declaredDependencyNode.value)) {
|
||||||
context.report({
|
context.report({
|
||||||
node: declaredDependencyNode,
|
node: declaredDependencyNode,
|
||||||
message:
|
message:
|
||||||
`The ${
|
`The ${
|
||||||
declaredDependencyNode.raw
|
declaredDependencyNode.raw
|
||||||
} string literal is not a valid dependency ` +
|
} literal is not a valid dependency ` +
|
||||||
`because it never changes. Did you mean to ` +
|
`because it never changes. ` +
|
||||||
`include ${
|
`Did you mean to include ${
|
||||||
declaredDependencyNode.value
|
declaredDependencyNode.value
|
||||||
} in the array instead?`,
|
} in the array instead?`,
|
||||||
});
|
});
|
||||||
|
@ -517,9 +518,9 @@ export default {
|
||||||
context.report({
|
context.report({
|
||||||
node: declaredDependencyNode,
|
node: declaredDependencyNode,
|
||||||
message:
|
message:
|
||||||
`The '${
|
`The ${
|
||||||
declaredDependencyNode.raw
|
declaredDependencyNode.raw
|
||||||
}' literal is not a valid dependency ` +
|
} literal is not a valid dependency ` +
|
||||||
'because it never changes. You can safely remove it.',
|
'because it never changes. You can safely remove it.',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -570,13 +571,12 @@ export default {
|
||||||
context.report({
|
context.report({
|
||||||
node: writeExpr,
|
node: writeExpr,
|
||||||
message:
|
message:
|
||||||
`Assignments to the '${key}' variable from inside a React ${context.getSource(
|
`Assignments to the '${key}' variable from inside React Hook ` +
|
||||||
reactiveHook,
|
`${context.getSource(reactiveHook)} will be lost after each ` +
|
||||||
)} Hook ` +
|
`render. To preserve the value over time, store it in a useRef ` +
|
||||||
`will not persist between re-renders. ` +
|
`Hook and keep the mutable value in the '.current' property. ` +
|
||||||
`If it's only needed by this Hook, move the variable inside it. ` +
|
`Otherwise, you can move this variable directly inside ` +
|
||||||
`Alternatively, declare a ref with the useRef Hook, ` +
|
`${context.getSource(reactiveHook)}.`,
|
||||||
`and keep the mutable value in its 'current' property.`,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -644,7 +644,10 @@ export default {
|
||||||
fn.name.name
|
fn.name.name
|
||||||
}' definition into its own useCallback() Hook.`;
|
}' definition into its own useCallback() Hook.`;
|
||||||
}
|
}
|
||||||
|
// TODO: What if the function needs to change on every render anyway?
|
||||||
|
// Should we suggest removing effect deps as an appropriate fix too?
|
||||||
context.report({
|
context.report({
|
||||||
|
// TODO: Why not report this at the dependency site?
|
||||||
node: fn.node,
|
node: fn.node,
|
||||||
message,
|
message,
|
||||||
fix(fixer) {
|
fix(fixer) {
|
||||||
|
@ -654,10 +657,10 @@ export default {
|
||||||
return [
|
return [
|
||||||
// TODO: also add an import?
|
// TODO: also add an import?
|
||||||
fixer.insertTextBefore(fn.node.init, 'useCallback('),
|
fixer.insertTextBefore(fn.node.init, 'useCallback('),
|
||||||
// TODO: ideally we'd gather deps here but it would
|
// TODO: ideally we'd gather deps here but it would require
|
||||||
// require restructuring the rule code. For now,
|
// restructuring the rule code. This will cause a new lint
|
||||||
// this is fine. Note we're intentionally not adding
|
// error to appear immediately for useCallback. Note we're
|
||||||
// [] because that changes semantics.
|
// not adding [] because would that changes semantics.
|
||||||
fixer.insertTextAfter(fn.node.init, ')'),
|
fixer.insertTextAfter(fn.node.init, ')'),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -731,7 +734,7 @@ export default {
|
||||||
if (badRef !== null) {
|
if (badRef !== null) {
|
||||||
extraWarning =
|
extraWarning =
|
||||||
` Mutable values like '${badRef}' aren't valid dependencies ` +
|
` Mutable values like '${badRef}' aren't valid dependencies ` +
|
||||||
"because their mutation doesn't re-render the component.";
|
"because mutating them doesn't re-render the component.";
|
||||||
} else if (externalDependencies.size > 0) {
|
} else if (externalDependencies.size > 0) {
|
||||||
const dep = Array.from(externalDependencies)[0];
|
const dep = Array.from(externalDependencies)[0];
|
||||||
// Don't show this warning for things that likely just got moved *inside* the callback
|
// Don't show this warning for things that likely just got moved *inside* the callback
|
||||||
|
@ -739,7 +742,7 @@ export default {
|
||||||
if (!scope.set.has(dep)) {
|
if (!scope.set.has(dep)) {
|
||||||
extraWarning =
|
extraWarning =
|
||||||
` Outer scope values like '${dep}' aren't valid dependencies ` +
|
` Outer scope values like '${dep}' aren't valid dependencies ` +
|
||||||
`because their mutation doesn't re-render the component.`;
|
`because mutating them doesn't re-render the component.`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -779,9 +782,10 @@ export default {
|
||||||
}
|
}
|
||||||
if (isPropsOnlyUsedInMembers) {
|
if (isPropsOnlyUsedInMembers) {
|
||||||
extraWarning =
|
extraWarning =
|
||||||
` However, the preferred fix is to destructure the 'props' ` +
|
` However, 'props' will change when *any* prop changes, so the ` +
|
||||||
`object outside of the ${reactiveHookName} call and ` +
|
`preferred fix is to destructure the 'props' object outside of ` +
|
||||||
`refer to specific props directly by their names.`;
|
`the ${reactiveHookName} call and refer to those specific props ` +
|
||||||
|
`inside ${context.getSource(reactiveHook)}.`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -829,8 +833,7 @@ export default {
|
||||||
});
|
});
|
||||||
if (missingCallbackDep !== null) {
|
if (missingCallbackDep !== null) {
|
||||||
extraWarning =
|
extraWarning =
|
||||||
` If specifying '${missingCallbackDep}'` +
|
` If '${missingCallbackDep}' changes too often, ` +
|
||||||
` makes the dependencies change too often, ` +
|
|
||||||
`find the parent component that defines it ` +
|
`find the parent component that defines it ` +
|
||||||
`and wrap that definition in useCallback.`;
|
`and wrap that definition in useCallback.`;
|
||||||
}
|
}
|
||||||
|
@ -906,20 +909,21 @@ export default {
|
||||||
break;
|
break;
|
||||||
case 'inlineReducer':
|
case 'inlineReducer':
|
||||||
extraWarning =
|
extraWarning =
|
||||||
` You can also replace useState with an inline useReducer ` +
|
` If '${setStateRecommendation.setter}' needs the ` +
|
||||||
`if '${setStateRecommendation.setter}' needs the ` +
|
`current value of '${setStateRecommendation.missingDep}', ` +
|
||||||
`current value of '${setStateRecommendation.missingDep}'.`;
|
`you can also switch to useReducer instead of useState and ` +
|
||||||
|
`read '${setStateRecommendation.missingDep}' in the reducer.`;
|
||||||
break;
|
break;
|
||||||
case 'updater':
|
case 'updater':
|
||||||
extraWarning =
|
extraWarning =
|
||||||
` You can also write '${
|
` You can also do a functional update '${
|
||||||
setStateRecommendation.setter
|
setStateRecommendation.setter
|
||||||
}(${setStateRecommendation.missingDep.substring(
|
}(${setStateRecommendation.missingDep.substring(
|
||||||
0,
|
0,
|
||||||
1,
|
1,
|
||||||
)} => ...)' if you only use '${
|
)} => ...)' if you only need '${
|
||||||
setStateRecommendation.missingDep
|
setStateRecommendation.missingDep
|
||||||
}'` + ` for the '${setStateRecommendation.setter}' call.`;
|
}'` + ` in the '${setStateRecommendation.setter}' call.`;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error('Unknown case.');
|
throw new Error('Unknown case.');
|
||||||
|
|
Loading…
Reference in New Issue