Update eslint rule exhaustive deps to use new suggestions feature (#17385)
This closes #16313
Will Douglas committed
Feb 17, 2020 at 13:24 UTC
93a229bab59f94e214256582c55d3b6c1fc2b958
2 files changed
+3335
-2052
packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js
+3282
-2022
@@ -19,6 +19,16 @@ ESLintTester.setDefaultConfig({
19
},
20
});
21
22
+/**
23
+ * A string template tag that removes padding from the left side of multi-line strings
24
+ * @param {Array} strings array of code strings (only one expected)
25
+ */
26
+function normalizeIndent(strings) {
27
+ const codeLines = strings[0].split('\n');
28
+ const leftPadding = codeLines[1].match(/\s+/)[0];
29
+ return codeLines.map(line => line.substr(leftPadding.length)).join('\n');
30
+}
31
+
32
// ***************************************************
33
// For easier local testing, you can add to any case:
34
// {
@@ -32,7 +42,7 @@ ESLintTester.setDefaultConfig({
42
const tests = {
43
valid: [
44
{
35
- code: `
45
+ code: normalizeIndent`
46
function MyComponent() {
47
const local = {};
48
useEffect(() => {
@@ -42,7 +52,7 @@ const tests = {
52
`,
53
},
54
{
45
- code: `
55
+ code: normalizeIndent`
56
function MyComponent() {
57
useEffect(() => {
58
const local = {};
@@ -52,7 +62,7 @@ const tests = {
62
`,
63
},
64
{
55
- code: `
65
+ code: normalizeIndent`
66
function MyComponent() {
67
const local = {};
68
useEffect(() => {
@@ -67,7 +77,7 @@ const tests = {
77
// to be an import that hasn't been added yet, or
78
// a component-level variable. Ignore it until it
79
// gets defined (a different rule would flag it anyway).
70
- code: `
80
+ code: normalizeIndent`
81
function MyComponent() {
82
useEffect(() => {
83
console.log(props.foo);
@@ -76,7 +86,7 @@ const tests = {
86
`,
87
},
88
{
79
- code: `
89
+ code: normalizeIndent`
90
function MyComponent() {
91
const local1 = {};
92
{
@@ -90,7 +100,7 @@ const tests = {
100
`,
101
},
102
{
93
- code: `
103
+ code: normalizeIndent`
104
function MyComponent() {
105
const local1 = {};
106
{
@@ -104,7 +114,7 @@ const tests = {
114
`,
115
},
116
{
107
- code: `
117
+ code: normalizeIndent`
118
function MyComponent() {
119
const local1 = {};
120
function MyNestedComponent() {
@@ -118,7 +128,7 @@ const tests = {
128
`,
129
},
130
{
121
- code: `
131
+ code: normalizeIndent`
132
function MyComponent() {
133
const local = {};
134
useEffect(() => {
@@ -129,7 +139,7 @@ const tests = {
139
`,
140
},
141
{
132
- code: `
142
+ code: normalizeIndent`
143
function MyComponent() {
144
useEffect(() => {
145
console.log(unresolved);
@@ -138,7 +148,7 @@ const tests = {
148
`,
149
},
150
{
141
- code: `
151
+ code: normalizeIndent`
152
function MyComponent() {
153
const local = {};
154
useEffect(() => {
@@ -149,7 +159,7 @@ const tests = {
159
},
160
{
161
// Regression test
152
- code: `
162
+ code: normalizeIndent`
163
function MyComponent({ foo }) {
164
useEffect(() => {
165
console.log(foo.length);
@@ -159,7 +169,7 @@ const tests = {
169
},
170
{
171
// Regression test
162
- code: `
172
+ code: normalizeIndent`
173
function MyComponent({ foo }) {
174
useEffect(() => {
175
console.log(foo.length);
@@ -170,7 +180,7 @@ const tests = {
180
},
181
{
182
// Regression test
173
- code: `
183
+ code: normalizeIndent`
184
function MyComponent({ history }) {
185
useEffect(() => {
186
return history.listen();
@@ -180,7 +190,7 @@ const tests = {
190
},
191
{
192
// Valid because they have meaning without deps.
183
- code: `
193
+ code: normalizeIndent`
194
function MyComponent(props) {
195
useEffect(() => {});
196
useLayoutEffect(() => {});
@@ -189,7 +199,7 @@ const tests = {
199
`,
200
},
201
{
192
- code: `
202
+ code: normalizeIndent`
203
function MyComponent(props) {
204
useEffect(() => {
205
console.log(props.foo);
@@ -198,7 +208,7 @@ const tests = {
208
`,
209
},
210
{
201
- code: `
211
+ code: normalizeIndent`
212
function MyComponent(props) {
213
useEffect(() => {
214
console.log(props.foo);
@@ -208,7 +218,7 @@ const tests = {
218
`,
219
},
220
{
211
- code: `
221
+ code: normalizeIndent`
222
function MyComponent(props) {
223
useEffect(() => {
224
console.log(props.foo);
@@ -218,7 +228,7 @@ const tests = {
228
`,
229
},
230
{
221
- code: `
231
+ code: normalizeIndent`
232
function MyComponent(props) {
233
const local = {};
234
useEffect(() => {
@@ -233,7 +243,7 @@ const tests = {
243
// [props, props.foo] is technically unnecessary ('props' covers 'props.foo').
244
// However, it's valid for effects to over-specify their deps.
245
// So we don't warn about this. We *would* warn about useMemo/useCallback.
236
- code: `
246
+ code: normalizeIndent`
247
function MyComponent(props) {
248
const local = {};
249
useEffect(() => {
@@ -250,7 +260,7 @@ const tests = {
260
`,
261
},
262
{
253
- code: `
263
+ code: normalizeIndent`
264
function MyComponent(props) {
265
useCustomEffect(() => {
266
console.log(props.foo);
@@ -260,7 +270,7 @@ const tests = {
270
options: [{additionalHooks: 'useCustomEffect'}],
271
},
272
{
263
- code: `
273
+ code: normalizeIndent`
274
function MyComponent(props) {
275
useCustomEffect(() => {
276
console.log(props.foo);
@@ -270,7 +280,7 @@ const tests = {
280
options: [{additionalHooks: 'useCustomEffect'}],
281
},
282
{
273
- code: `
283
+ code: normalizeIndent`
284
function MyComponent(props) {
285
useCustomEffect(() => {
286
console.log(props.foo);
@@ -281,7 +291,7 @@ const tests = {
291
},
292
{
293
// Valid because we don't care about hooks outside of components.
284
- code: `
294
+ code: normalizeIndent`
295
const local = {};
296
useEffect(() => {
297
console.log(local);
@@ -290,7 +300,7 @@ const tests = {
300
},
301
{
302
// Valid because we don't care about hooks outside of components.
293
- code: `
303
+ code: normalizeIndent`
304
const local1 = {};
305
{
306
const local2 = {};
@@ -302,7 +312,7 @@ const tests = {
312
`,
313
},
314
{
305
- code: `
315
+ code: normalizeIndent`
316
function MyComponent() {
317
const ref = useRef();
318
useEffect(() => {
@@ -312,7 +322,7 @@ const tests = {
322
`,
323
},
324
{
315
- code: `
325
+ code: normalizeIndent`
326
function MyComponent() {
327
const ref = useRef();
328
useEffect(() => {
@@ -322,7 +332,7 @@ const tests = {
332
`,
333
},
334
{
325
- code: `
335
+ code: normalizeIndent`
336
function MyComponent({ maybeRef2, foo }) {
337
const definitelyRef1 = useRef();
338
const definitelyRef2 = useRef();
@@ -376,7 +386,7 @@ const tests = {
386
`,
387
},
388
{
379
- code: `
389
+ code: normalizeIndent`
390
function MyComponent({ maybeRef2 }) {
391
const definitelyRef1 = useRef();
392
const definitelyRef2 = useRef();
@@ -434,7 +444,7 @@ const tests = {
444
`,
445
},
446
{
437
- code: `
447
+ code: normalizeIndent`
448
const MyComponent = forwardRef((props, ref) => {
449
useImperativeHandle(ref, () => ({
450
focus() {
@@ -445,7 +455,7 @@ const tests = {
455
`,
456
},
457
{
448
- code: `
458
+ code: normalizeIndent`
459
const MyComponent = forwardRef((props, ref) => {
460
useImperativeHandle(ref, () => ({
461
focus() {
@@ -459,7 +469,7 @@ const tests = {
469
// This is not ideal but warning would likely create
470
// too many false positives. We do, however, prevent
471
// direct assignments.
462
- code: `
472
+ code: normalizeIndent`
473
function MyComponent(props) {
474
let obj = {};
475
useEffect(() => {
@@ -472,7 +482,7 @@ const tests = {
482
// Valid because we assign ref.current
483
// ourselves. Therefore it's likely not
484
// a ref managed by React.
475
- code: `
485
+ code: normalizeIndent`
486
function MyComponent() {
487
const myRef = useRef();
488
useEffect(() => {
@@ -490,7 +500,7 @@ const tests = {
500
// Valid because we assign ref.current
501
// ourselves. Therefore it's likely not
502
// a ref managed by React.
493
- code: `
503
+ code: normalizeIndent`
504
function useMyThing(myRef) {
505
useEffect(() => {
506
const handleMove = () => {};
@@ -504,7 +514,7 @@ const tests = {
514
},
515
{
516
// Valid because the ref is captured.
507
- code: `
517
+ code: normalizeIndent`
518
function MyComponent() {
519
const myRef = useRef();
520
useEffect(() => {
@@ -519,7 +529,7 @@ const tests = {
529
},
530
{
531
// Valid because the ref is captured.
522
- code: `
532
+ code: normalizeIndent`
533
function useMyThing(myRef) {
534
useEffect(() => {
535
const handleMove = () => {};
@@ -533,7 +543,7 @@ const tests = {
543
},
544
{
545
// Valid because it's not an effect.
536
- code: `
546
+ code: normalizeIndent`
547
function useMyThing(myRef) {
548
useCallback(() => {
549
const handleMouse = () => {};
@@ -551,7 +561,7 @@ const tests = {
561
},
562
{
563
// Valid because we read ref.current in a function that isn't cleanup.
554
- code: `
564
+ code: normalizeIndent`
565
function useMyThing() {
566
const myRef = useRef();
567
useEffect(() => {
@@ -567,7 +577,7 @@ const tests = {
577
},
578
{
579
// Valid because we read ref.current in a function that isn't cleanup.
570
- code: `
580
+ code: normalizeIndent`
581
function useMyThing() {
582
const myRef = useRef();
583
useEffect(() => {
@@ -583,7 +593,7 @@ const tests = {
593
},
594
{
595
// Valid because it's a primitive constant.
586
- code: `
596
+ code: normalizeIndent`
597
function MyComponent() {
598
const local1 = 42;
599
const local2 = '42';
@@ -598,7 +608,7 @@ const tests = {
608
},
609
{
610
// It's not a mistake to specify constant values though.
601
- code: `
611
+ code: normalizeIndent`
612
function MyComponent() {
613
const local1 = 42;
614
const local2 = '42';
@@ -613,7 +623,7 @@ const tests = {
623
},
624
{
625
// It is valid for effects to over-specify their deps.
616
- code: `
626
+ code: normalizeIndent`
627
function MyComponent(props) {
628
const local = props.local;
629
useEffect(() => {}, [local]);
@@ -623,7 +633,7 @@ const tests = {
633
{
634
// Valid even though activeTab is "unused".
635
// We allow over-specifying deps for effects, but not callbacks or memo.
626
- code: `
636
+ code: normalizeIndent`
637
function Foo({ activeTab }) {
638
useEffect(() => {
639
window.scrollTo(0, 0);
@@ -634,7 +644,7 @@ const tests = {
644
{
645
// It is valid to specify broader effect deps than strictly necessary.
646
// Don't warn for this.
637
- code: `
647
+ code: normalizeIndent`
648
function MyComponent(props) {
649
useEffect(() => {
650
console.log(props.foo.bar.baz);
@@ -654,7 +664,7 @@ const tests = {
664
{
665
// It is *also* valid to specify broader memo/callback deps than strictly necessary.
666
// Don't warn for this either.
657
- code: `
667
+ code: normalizeIndent`
668
function MyComponent(props) {
669
const fn = useCallback(() => {
670
console.log(props.foo.bar.baz);
@@ -674,7 +684,7 @@ const tests = {
684
{
685
// Declaring handleNext is optional because
686
// it doesn't use anything in the function scope.
677
- code: `
687
+ code: normalizeIndent`
688
function MyComponent(props) {
689
function handleNext1() {
690
console.log('hello');
@@ -700,7 +710,7 @@ const tests = {
710
{
711
// Declaring handleNext is optional because
712
// it doesn't use anything in the function scope.
703
- code: `
713
+ code: normalizeIndent`
714
function MyComponent(props) {
715
function handleNext() {
716
console.log('hello');
@@ -720,7 +730,7 @@ const tests = {
730
{
731
// Declaring handleNext is optional because
732
// everything they use is fully static.
723
- code: `
733
+ code: normalizeIndent`
734
function MyComponent(props) {
735
let [, setState] = useState();
736
let [, dispatch] = React.useReducer();
@@ -751,7 +761,7 @@ const tests = {
761
`,
762
},
763
{
754
- code: `
764
+ code: normalizeIndent`
765
function useInterval(callback, delay) {
766
const savedCallback = useRef();
767
useEffect(() => {
@@ -770,7 +780,7 @@ const tests = {
780
`,
781
},
782
{
773
- code: `
783
+ code: normalizeIndent`
784
function Counter() {
785
const [count, setCount] = useState(0);
786
@@ -786,7 +796,7 @@ const tests = {
796
`,
797
},
798
{
789
- code: `
799
+ code: normalizeIndent`
800
function Counter() {
801
const [count, setCount] = useState(0);
802
@@ -806,7 +816,7 @@ const tests = {
816
`,
817
},
818
{
809
- code: `
819
+ code: normalizeIndent`
820
function Counter() {
821
const [count, dispatch] = useReducer((state, action) => {
822
if (action === 'inc') {
@@ -826,7 +836,7 @@ const tests = {
836
`,
837
},
838
{
829
- code: `
839
+ code: normalizeIndent`
840
function Counter() {
841
const [count, dispatch] = useReducer((state, action) => {
842
if (action === 'inc') {
@@ -849,7 +859,7 @@ const tests = {
859
},
860
{
861
// Regression test for a crash
852
- code: `
862
+ code: normalizeIndent`
863
function Podcasts() {
864
useEffect(() => {
865
setPodcasts([]);
@@ -859,7 +869,7 @@ const tests = {
869
`,
870
},
871
{
862
- code: `
872
+ code: normalizeIndent`
873
function withFetch(fetchPodcasts) {
874
return function Podcasts({ id }) {
875
let [podcasts, setPodcasts] = useState(null);
@@ -871,7 +881,7 @@ const tests = {
881
`,
882
},
883
{
874
- code: `
884
+ code: normalizeIndent`
885
function Podcasts({ id }) {
886
let [podcasts, setPodcasts] = useState(null);
887
useEffect(() => {
@@ -884,7 +894,7 @@ const tests = {
894
`,
895
},
896
{
887
- code: `
897
+ code: normalizeIndent`
898
function Counter() {
899
let [count, setCount] = useState(0);
900
@@ -904,7 +914,7 @@ const tests = {
914
`,
915
},
916
{
907
- code: `
917
+ code: normalizeIndent`
918
function Counter() {
919
let [count, setCount] = useState(0);
920
@@ -924,7 +934,7 @@ const tests = {
934
`,
935
},
936
{
927
- code: `
937
+ code: normalizeIndent`
938
import increment from './increment';
939
function Counter() {
940
let [count, setCount] = useState(0);
@@ -941,7 +951,7 @@ const tests = {
951
`,
952
},
953
{
944
- code: `
954
+ code: normalizeIndent`
955
function withStuff(increment) {
956
return function Counter() {
957
let [count, setCount] = useState(0);
@@ -959,7 +969,7 @@ const tests = {
969
`,
970
},
971
{
962
- code: `
972
+ code: normalizeIndent`
973
function App() {
974
const [query, setQuery] = useState('react');
975
const [state, setState] = useState(null);
@@ -982,7 +992,7 @@ const tests = {
992
`,
993
},
994
{
985
- code: `
995
+ code: normalizeIndent`
996
function Example() {
997
const foo = useCallback(() => {
998
foo();
@@ -991,7 +1001,7 @@ const tests = {
1001
`,
1002
},
1003
{
994
- code: `
1004
+ code: normalizeIndent`
1005
function Example({ prop }) {
1006
const foo = useCallback(() => {
1007
if (prop) {
@@ -1002,7 +1012,7 @@ const tests = {
1012
`,
1013
},
1014
{
1005
- code: `
1015
+ code: normalizeIndent`
1016
function Hello() {
1017
const [state, setState] = useState(0);
1018
useEffect(() => {
@@ -1015,7 +1025,7 @@ const tests = {
1025
},
1026
// Ignore Generic Type Variables for arrow functions
1027
{
1018
- code: `
1028
+ code: normalizeIndent`
1029
function Example({ prop }) {
1030
const bar = useEffect(<T>(a: T): Hello => {
1031
prop();
@@ -1025,7 +1035,7 @@ const tests = {
1035
},
1036
// Ignore arguments keyword for arrow functions.
1037
{
1028
- code: `
1038
+ code: normalizeIndent`
1039
function Example() {
1040
useEffect(() => {
1041
arguments
@@ -1034,7 +1044,7 @@ const tests = {
1044
`,
1045
},
1046
{
1037
- code: `
1047
+ code: normalizeIndent`
1048
function Example() {
1049
useEffect(() => {
1050
const bar = () => {
@@ -1048,7 +1058,7 @@ const tests = {
1058
],
1059
invalid: [
1060
{
1051
- code: `
1061
+ code: normalizeIndent`
1062
function MyComponent() {
1063
const local = {};
1064
useEffect(() => {
@@ -1056,24 +1066,32 @@ const tests = {
1066
}, []);
1067
}
1068
`,
1059
- output: `
1060
- function MyComponent() {
1061
- const local = {};
1062
- useEffect(() => {
1063
- console.log(local);
1064
- }, [local]);
1065
- }
1066
- `,
1069
errors: [
1068
- "React Hook useEffect has a missing dependency: 'local'. " +
1069
- 'Either include it or remove the dependency array.',
1070
+ {
1071
+ message:
1072
+ "React Hook useEffect has a missing dependency: 'local'. " +
1073
+ 'Either include it or remove the dependency array.',
1074
+ suggestions: [
1075
+ {
1076
+ desc: 'Update the dependencies array to be: [local]',
1077
+ output: normalizeIndent`
1078
+ function MyComponent() {
1079
+ const local = {};
1080
+ useEffect(() => {
1081
+ console.log(local);
1082
+ }, [local]);
1083
+ }
1084
+ `,
1085
+ },
1086
+ ],
1087
+ },
1088
],
1089
},
1090
{
1091
// Note: we *could* detect it's a primitive and never assigned
1092
// even though it's not a constant -- but we currently don't.
1093
// So this is an error.
1076
- code: `
1094
+ code: normalizeIndent`
1095
function MyComponent() {
1096
let local = 42;
1097
useEffect(() => {
@@ -1081,22 +1099,30 @@ const tests = {
1099
}, []);
1100
}
1101
`,
1084
- output: `
1085
- function MyComponent() {
1086
- let local = 42;
1087
- useEffect(() => {
1088
- console.log(local);
1089
- }, [local]);
1090
- }
1091
- `,
1102
errors: [
1093
- "React Hook useEffect has a missing dependency: 'local'. " +
1094
- 'Either include it or remove the dependency array.',
1103
+ {
1104
+ message:
1105
+ "React Hook useEffect has a missing dependency: 'local'. " +
1106
+ 'Either include it or remove the dependency array.',
1107
+ suggestions: [
1108
+ {
1109
+ desc: 'Update the dependencies array to be: [local]',
1110
+ output: normalizeIndent`
1111
+ function MyComponent() {
1112
+ let local = 42;
1113
+ useEffect(() => {
1114
+ console.log(local);
1115
+ }, [local]);
1116
+ }
1117
+ `,
1118
+ },
1119
+ ],
1120
+ },
1121
],
1122
},
1123
{
1124
// Regexes are literals but potentially stateful.
1099
- code: `
1125
+ code: normalizeIndent`
1126
function MyComponent() {
1127
const local = /foo/;
1128
useEffect(() => {
@@ -1104,44 +1130,54 @@ const tests = {
1130
}, []);
1131
}
1132
`,
1107
- output: `
1108
- function MyComponent() {
1109
- const local = /foo/;
1110
- useEffect(() => {
1111
- console.log(local);
1112
- }, [local]);
1113
- }
1114
- `,
1133
errors: [
1116
- "React Hook useEffect has a missing dependency: 'local'. " +
1117
- 'Either include it or remove the dependency array.',
1134
+ {
1135
+ message:
1136
+ "React Hook useEffect has a missing dependency: 'local'. " +
1137
+ 'Either include it or remove the dependency array.',
1138
+ suggestions: [
1139
+ {
1140
+ desc: 'Update the dependencies array to be: [local]',
1141
+ output: normalizeIndent`
1142
+ function MyComponent() {
1143
+ const local = /foo/;
1144
+ useEffect(() => {
1145
+ console.log(local);
1146
+ }, [local]);
1147
+ }
1148
+ `,
1149
+ },
1150
+ ],
1151
+ },
1152
],
1153
},
1154
{
1155
// Invalid because they don't have a meaning without deps.
1122
- code: `
1156
+ code: normalizeIndent`
1157
function MyComponent(props) {
1158
const value = useMemo(() => { return 2*2; });
1159
const fn = useCallback(() => { alert('foo'); });
1160
}
1161
`,
1162
// We don't know what you meant.
1129
- output: `
1130
- function MyComponent(props) {
1131
- const value = useMemo(() => { return 2*2; });
1132
- const fn = useCallback(() => { alert('foo'); });
1133
- }
1134
- `,
1163
errors: [
1136
- 'React Hook useMemo does nothing when called with only one argument. ' +
1137
- 'Did you forget to pass an array of dependencies?',
1138
- 'React Hook useCallback does nothing when called with only one argument. ' +
1139
- 'Did you forget to pass an array of dependencies?',
1164
+ {
1165
+ message:
1166
+ 'React Hook useMemo does nothing when called with only one argument. ' +
1167
+ 'Did you forget to pass an array of dependencies?',
1168
+ suggestions: undefined,
1169
+ },
1170
+ {
1171
+ message:
1172
+ 'React Hook useCallback does nothing when called with only one argument. ' +
1173
+ 'Did you forget to pass an array of dependencies?',
1174
+ suggestions: undefined,
1175
+ },
1176
],
1177
},
1178
{
1179
// Regression test
1144
- code: `
1180
+ code: normalizeIndent`
1181
function MyComponent() {
1182
const local = {};
1183
useEffect(() => {
@@ -1151,24 +1187,32 @@ const tests = {
1187
}, []);
1188
}
1189
`,
1154
- output: `
1155
- function MyComponent() {
1156
- const local = {};
1157
- useEffect(() => {
1158
- if (true) {
1159
- console.log(local);
1160
- }
1161
- }, [local]);
1162
- }
1163
- `,
1190
errors: [
1165
- "React Hook useEffect has a missing dependency: 'local'. " +
1166
- 'Either include it or remove the dependency array.',
1191
+ {
1192
+ message:
1193
+ "React Hook useEffect has a missing dependency: 'local'. " +
1194
+ 'Either include it or remove the dependency array.',
1195
+ suggestions: [
1196
+ {
1197
+ desc: 'Update the dependencies array to be: [local]',
1198
+ output: normalizeIndent`
1199
+ function MyComponent() {
1200
+ const local = {};
1201
+ useEffect(() => {
1202
+ if (true) {
1203
+ console.log(local);
1204
+ }
1205
+ }, [local]);
1206
+ }
1207
+ `,
1208
+ },
1209
+ ],
1210
+ },
1211
],
1212
},
1213
{
1214
// Regression test
1171
- code: `
1215
+ code: normalizeIndent`
1216
function MyComponent() {
1217
const local = {};
1218
useEffect(() => {
@@ -1178,24 +1222,32 @@ const tests = {
1222
}, []);
1223
}
1224
`,
1181
- output: `
1182
- function MyComponent() {
1183
- const local = {};
1184
- useEffect(() => {
1185
- try {
1186
- console.log(local);
1187
- } finally {}
1188
- }, [local]);
1189
- }
1190
- `,
1225
errors: [
1192
- "React Hook useEffect has a missing dependency: 'local'. " +
1193
- 'Either include it or remove the dependency array.',
1226
+ {
1227
+ message:
1228
+ "React Hook useEffect has a missing dependency: 'local'. " +
1229
+ 'Either include it or remove the dependency array.',
1230
+ suggestions: [
1231
+ {
1232
+ desc: 'Update the dependencies array to be: [local]',
1233
+ output: normalizeIndent`
1234
+ function MyComponent() {
1235
+ const local = {};
1236
+ useEffect(() => {
1237
+ try {
1238
+ console.log(local);
1239
+ } finally {}
1240
+ }, [local]);
1241
+ }
1242
+ `,
1243
+ },
1244
+ ],
1245
+ },
1246
],
1247
},
1248
{
1249
// Regression test
1198
- code: `
1250
+ code: normalizeIndent`
1251
function MyComponent() {
1252
const local = {};
1253
useEffect(() => {
@@ -1206,24 +1258,32 @@ const tests = {
1258
}, []);
1259
}
1260
`,
1209
- output: `
1210
- function MyComponent() {
1211
- const local = {};
1212
- useEffect(() => {
1213
- function inner() {
1214
- console.log(local);
1215
- }
1216
- inner();
1217
- }, [local]);
1218
- }
1219
- `,
1261
errors: [
1221
- "React Hook useEffect has a missing dependency: 'local'. " +
1222
- 'Either include it or remove the dependency array.',
1262
+ {
1263
+ message:
1264
+ "React Hook useEffect has a missing dependency: 'local'. " +
1265
+ 'Either include it or remove the dependency array.',
1266
+ suggestions: [
1267
+ {
1268
+ desc: 'Update the dependencies array to be: [local]',
1269
+ output: normalizeIndent`
1270
+ function MyComponent() {
1271
+ const local = {};
1272
+ useEffect(() => {
1273
+ function inner() {
1274
+ console.log(local);
1275
+ }
1276
+ inner();
1277
+ }, [local]);
1278
+ }
1279
+ `,
1280
+ },
1281
+ ],
1282
+ },
1283
],
1284
},
1285
{
1226
- code: `
1286
+ code: normalizeIndent`
1287
function MyComponent() {
1288
const local1 = {};
1289
{
@@ -1235,25 +1295,33 @@ const tests = {
1295
}
1296
}
1297
`,
1238
- output: `
1239
- function MyComponent() {
1240
- const local1 = {};
1241
- {
1242
- const local2 = {};
1243
- useEffect(() => {
1244
- console.log(local1);
1245
- console.log(local2);
1246
- }, [local1, local2]);
1247
- }
1248
- }
1249
- `,
1298
errors: [
1251
- "React Hook useEffect has missing dependencies: 'local1' and 'local2'. " +
1252
- 'Either include them or remove the dependency array.',
1299
+ {
1300
+ message:
1301
+ "React Hook useEffect has missing dependencies: 'local1' and 'local2'. " +
1302
+ 'Either include them or remove the dependency array.',
1303
+ suggestions: [
1304
+ {
1305
+ desc: 'Update the dependencies array to be: [local1, local2]',
1306
+ output: normalizeIndent`
1307
+ function MyComponent() {
1308
+ const local1 = {};
1309
+ {
1310
+ const local2 = {};
1311
+ useEffect(() => {
1312
+ console.log(local1);
1313
+ console.log(local2);
1314
+ }, [local1, local2]);
1315
+ }
1316
+ }
1317
+ `,
1318
+ },
1319
+ ],
1320
+ },
1321
],
1322
},
1323
{
1256
- code: `
1324
+ code: normalizeIndent`
1325
function MyComponent() {
1326
const local1 = {};
1327
const local2 = {};
@@ -1263,23 +1331,31 @@ const tests = {
1331
}, [local1]);
1332
}
1333
`,
1266
- output: `
1267
- function MyComponent() {
1268
- const local1 = {};
1269
- const local2 = {};
1270
- useEffect(() => {
1271
- console.log(local1);
1272
- console.log(local2);
1273
- }, [local1, local2]);
1274
- }
1275
- `,
1334
errors: [
1277
- "React Hook useEffect has a missing dependency: 'local2'. " +
1278
- 'Either include it or remove the dependency array.',
1335
+ {
1336
+ message:
1337
+ "React Hook useEffect has a missing dependency: 'local2'. " +
1338
+ 'Either include it or remove the dependency array.',
1339
+ suggestions: [
1340
+ {
1341
+ desc: 'Update the dependencies array to be: [local1, local2]',
1342
+ output: normalizeIndent`
1343
+ function MyComponent() {
1344
+ const local1 = {};
1345
+ const local2 = {};
1346
+ useEffect(() => {
1347
+ console.log(local1);
1348
+ console.log(local2);
1349
+ }, [local1, local2]);
1350
+ }
1351
+ `,
1352
+ },
1353
+ ],
1354
+ },
1355
],
1356
},
1357
{
1282
- code: `
1358
+ code: normalizeIndent`
1359
function MyComponent() {
1360
const local1 = {};
1361
const local2 = {};
@@ -1288,22 +1364,30 @@ const tests = {
1364
}, [local1, local2]);
1365
}
1366
`,
1291
- output: `
1292
- function MyComponent() {
1293
- const local1 = {};
1294
- const local2 = {};
1295
- useMemo(() => {
1296
- console.log(local1);
1297
- }, [local1]);
1298
- }
1299
- `,
1367
errors: [
1301
- "React Hook useMemo has an unnecessary dependency: 'local2'. " +
1302
- 'Either exclude it or remove the dependency array.',
1368
+ {
1369
+ message:
1370
+ "React Hook useMemo has an unnecessary dependency: 'local2'. " +
1371
+ 'Either exclude it or remove the dependency array.',
1372
+ suggestions: [
1373
+ {
1374
+ desc: 'Update the dependencies array to be: [local1]',
1375
+ output: normalizeIndent`
1376
+ function MyComponent() {
1377
+ const local1 = {};
1378
+ const local2 = {};
1379
+ useMemo(() => {
1380
+ console.log(local1);
1381
+ }, [local1]);
1382
+ }
1383
+ `,
1384
+ },
1385
+ ],
1386
+ },
1387
],
1388
},
1389
{
1306
- code: `
1390
+ code: normalizeIndent`
1391
function MyComponent() {
1392
const local1 = {};
1393
function MyNestedComponent() {
@@ -1315,27 +1399,35 @@ const tests = {
1399
}
1400
}
1401
`,
1318
- output: `
1319
- function MyComponent() {
1320
- const local1 = {};
1321
- function MyNestedComponent() {
1322
- const local2 = {};
1323
- useCallback(() => {
1324
- console.log(local1);
1325
- console.log(local2);
1326
- }, [local2]);
1327
- }
1328
- }
1329
- `,
1402
errors: [
1331
- "React Hook useCallback has a missing dependency: 'local2'. " +
1332
- 'Either include it or remove the dependency array. ' +
1333
- "Outer scope values like 'local1' aren't valid dependencies " +
1334
- "because mutating them doesn't re-render the component.",
1403
+ {
1404
+ message:
1405
+ "React Hook useCallback has a missing dependency: 'local2'. " +
1406
+ 'Either include it or remove the dependency array. ' +
1407
+ "Outer scope values like 'local1' aren't valid dependencies " +
1408
+ "because mutating them doesn't re-render the component.",
1409
+ suggestions: [
1410
+ {
1411
+ desc: 'Update the dependencies array to be: [local2]',
1412
+ output: normalizeIndent`
1413
+ function MyComponent() {
1414
+ const local1 = {};
1415
+ function MyNestedComponent() {
1416
+ const local2 = {};
1417
+ useCallback(() => {
1418
+ console.log(local1);
1419
+ console.log(local2);
1420
+ }, [local2]);
1421
+ }
1422
+ }
1423
+ `,
1424
+ },
1425
+ ],
1426
+ },
1427
],
1428
},
1429
{
1338
- code: `
1430
+ code: normalizeIndent`
1431
function MyComponent() {
1432
const local = {};
1433
useEffect(() => {
@@ -1344,22 +1436,30 @@ const tests = {
1436
}, []);
1437
}
1438
`,
1347
- output: `
1348
- function MyComponent() {
1349
- const local = {};
1350
- useEffect(() => {
1351
- console.log(local);
1352
- console.log(local);
1353
- }, [local]);
1354
- }
1355
- `,
1439
errors: [
1357
- "React Hook useEffect has a missing dependency: 'local'. " +
1358
- 'Either include it or remove the dependency array.',
1440
+ {
1441
+ message:
1442
+ "React Hook useEffect has a missing dependency: 'local'. " +
1443
+ 'Either include it or remove the dependency array.',
1444
+ suggestions: [
1445
+ {
1446
+ desc: 'Update the dependencies array to be: [local]',
1447
+ output: normalizeIndent`
1448
+ function MyComponent() {
1449
+ const local = {};
1450
+ useEffect(() => {
1451
+ console.log(local);
1452
+ console.log(local);
1453
+ }, [local]);
1454
+ }
1455
+ `,
1456
+ },
1457
+ ],
1458
+ },
1459
],
1460
},
1461
{
1362
- code: `
1462
+ code: normalizeIndent`
1463
function MyComponent() {
1464
const local = {};
1465
useEffect(() => {
@@ -1368,80 +1468,112 @@ const tests = {
1468
}, [local, local]);
1469
}
1470
`,
1371
- output: `
1372
- function MyComponent() {
1373
- const local = {};
1374
- useEffect(() => {
1375
- console.log(local);
1376
- console.log(local);
1377
- }, [local]);
1378
- }
1379
- `,
1471
errors: [
1381
- "React Hook useEffect has a duplicate dependency: 'local'. " +
1382
- 'Either omit it or remove the dependency array.',
1472
+ {
1473
+ message:
1474
+ "React Hook useEffect has a duplicate dependency: 'local'. " +
1475
+ 'Either omit it or remove the dependency array.',
1476
+ suggestions: [
1477
+ {
1478
+ desc: 'Update the dependencies array to be: [local]',
1479
+ output: normalizeIndent`
1480
+ function MyComponent() {
1481
+ const local = {};
1482
+ useEffect(() => {
1483
+ console.log(local);
1484
+ console.log(local);
1485
+ }, [local]);
1486
+ }
1487
+ `,
1488
+ },
1489
+ ],
1490
+ },
1491
],
1492
},
1493
{
1386
- code: `
1494
+ code: normalizeIndent`
1495
function MyComponent() {
1496
useCallback(() => {}, [window]);
1497
}
1498
`,
1391
- output: `
1392
- function MyComponent() {
1393
- useCallback(() => {}, []);
1394
- }
1395
- `,
1499
errors: [
1397
- "React Hook useCallback has an unnecessary dependency: 'window'. " +
1398
- 'Either exclude it or remove the dependency array. ' +
1399
- "Outer scope values like 'window' aren't valid dependencies " +
1400
- "because mutating them doesn't re-render the component.",
1500
+ {
1501
+ message:
1502
+ "React Hook useCallback has an unnecessary dependency: 'window'. " +
1503
+ 'Either exclude it or remove the dependency array. ' +
1504
+ "Outer scope values like 'window' aren't valid dependencies " +
1505
+ "because mutating them doesn't re-render the component.",
1506
+ suggestions: [
1507
+ {
1508
+ desc: 'Update the dependencies array to be: []',
1509
+ output: normalizeIndent`
1510
+ function MyComponent() {
1511
+ useCallback(() => {}, []);
1512
+ }
1513
+ `,
1514
+ },
1515
+ ],
1516
+ },
1517
],
1518
},
1519
{
1520
// It is not valid for useCallback to specify extraneous deps
1521
// because it doesn't serve as a side effect trigger unlike useEffect.
1406
- code: `
1522
+ code: normalizeIndent`
1523
function MyComponent(props) {
1524
let local = props.foo;
1525
useCallback(() => {}, [local]);
1526
}
1527
`,
1412
- output: `
1413
- function MyComponent(props) {
1414
- let local = props.foo;
1415
- useCallback(() => {}, []);
1416
- }
1417
- `,
1528
errors: [
1419
- "React Hook useCallback has an unnecessary dependency: 'local'. " +
1420
- 'Either exclude it or remove the dependency array.',
1529
+ {
1530
+ message:
1531
+ "React Hook useCallback has an unnecessary dependency: 'local'. " +
1532
+ 'Either exclude it or remove the dependency array.',
1533
+ suggestions: [
1534
+ {
1535
+ desc: 'Update the dependencies array to be: []',
1536
+ output: normalizeIndent`
1537
+ function MyComponent(props) {
1538
+ let local = props.foo;
1539
+ useCallback(() => {}, []);
1540
+ }
1541
+ `,
1542
+ },
1543
+ ],
1544
+ },
1545
],
1546
},
1547
{
1424
- code: `
1548
+ code: normalizeIndent`
1549
function MyComponent({ history }) {
1550
useEffect(() => {
1551
return history.listen();
1552
}, []);
1553
}
1554
`,
1431
- output: `
1432
- function MyComponent({ history }) {
1433
- useEffect(() => {
1434
- return history.listen();
1435
- }, [history]);
1436
- }
1437
- `,
1555
errors: [
1439
- "React Hook useEffect has a missing dependency: 'history'. " +
1440
- 'Either include it or remove the dependency array.',
1556
+ {
1557
+ message:
1558
+ "React Hook useEffect has a missing dependency: 'history'. " +
1559
+ 'Either include it or remove the dependency array.',
1560
+ suggestions: [
1561
+ {
1562
+ desc: 'Update the dependencies array to be: [history]',
1563
+ output: normalizeIndent`
1564
+ function MyComponent({ history }) {
1565
+ useEffect(() => {
1566
+ return history.listen();
1567
+ }, [history]);
1568
+ }
1569
+ `,
1570
+ },
1571
+ ],
1572
+ },
1573
],
1574
},
1575
{
1444
- code: `
1576
+ code: normalizeIndent`
1577
function MyComponent({ history }) {
1578
useEffect(() => {
1579
return [
@@ -1451,107 +1583,148 @@ const tests = {
1583
}, []);
1584
}
1585
`,
1454
- output: `
1455
- function MyComponent({ history }) {
1456
- useEffect(() => {
1457
- return [
1458
- history.foo.bar[2].dobedo.listen(),
1459
- history.foo.bar().dobedo.listen[2]
1460
- ];
1461
- }, [history.foo]);
1462
- }
1463
- `,
1586
errors: [
1465
- "React Hook useEffect has a missing dependency: 'history.foo'. " +
1466
- 'Either include it or remove the dependency array.',
1587
+ {
1588
+ message:
1589
+ "React Hook useEffect has a missing dependency: 'history.foo'. " +
1590
+ 'Either include it or remove the dependency array.',
1591
+ suggestions: [
1592
+ {
1593
+ desc: 'Update the dependencies array to be: [history.foo]',
1594
+ output: normalizeIndent`
1595
+ function MyComponent({ history }) {
1596
+ useEffect(() => {
1597
+ return [
1598
+ history.foo.bar[2].dobedo.listen(),
1599
+ history.foo.bar().dobedo.listen[2]
1600
+ ];
1601
+ }, [history.foo]);
1602
+ }
1603
+ `,
1604
+ },
1605
+ ],
1606
+ },
1607
],
1608
},
1609
{
1470
- code: `
1471
- function MyComponent() {
1472
- useEffect(() => {}, ['foo']);
1473
- }
1474
- `,
1475
- // TODO: we could autofix this.
1476
- output: `
1610
+ code: normalizeIndent`
1611
function MyComponent() {
1612
useEffect(() => {}, ['foo']);
1613
}
1614
`,
1615
errors: [
1482
- // Don't assume user meant `foo` because it's not used in the effect.
1483
- "The 'foo' literal is not a valid dependency because it never changes. " +
1484
- 'You can safely remove it.',
1616
+ {
1617
+ message:
1618
+ // Don't assume user meant `foo` because it's not used in the effect.
1619
+ "The 'foo' literal is not a valid dependency because it never changes. " +
1620
+ 'You can safely remove it.',
1621
+ // TODO: provide suggestion.
1622
+ suggestions: undefined,
1623
+ },
1624
],
1625
},
1626
{
1488
- code: `
1627
+ code: normalizeIndent`
1628
function MyComponent({ foo, bar, baz }) {
1629
useEffect(() => {
1630
console.log(foo, bar, baz);
1631
}, ['foo', 'bar']);
1632
}
1633
`,
1495
- output: `
1496
- function MyComponent({ foo, bar, baz }) {
1497
- useEffect(() => {
1498
- console.log(foo, bar, baz);
1499
- }, [bar, baz, foo]);
1500
- }
1501
- `,
1634
errors: [
1503
- "React Hook useEffect has missing dependencies: 'bar', 'baz', and 'foo'. " +
1504
- 'Either include them or remove the dependency array.',
1505
- "The 'foo' literal is not a valid dependency because it never changes. " +
1506
- 'Did you mean to include foo in the array instead?',
1507
- "The 'bar' literal is not a valid dependency because it never changes. " +
1508
- 'Did you mean to include bar in the array instead?',
1635
+ {
1636
+ message:
1637
+ "React Hook useEffect has missing dependencies: 'bar', 'baz', and 'foo'. " +
1638
+ 'Either include them or remove the dependency array.',
1639
+ suggestions: [
1640
+ {
1641
+ desc: 'Update the dependencies array to be: [bar, baz, foo]',
1642
+ output: normalizeIndent`
1643
+ function MyComponent({ foo, bar, baz }) {
1644
+ useEffect(() => {
1645
+ console.log(foo, bar, baz);
1646
+ }, [bar, baz, foo]);
1647
+ }
1648
+ `,
1649
+ },
1650
+ ],
1651
+ },
1652
+ {
1653
+ message:
1654
+ "The 'foo' literal is not a valid dependency because it never changes. " +
1655
+ 'Did you mean to include foo in the array instead?',
1656
+ suggestions: undefined,
1657
+ },
1658
+ {
1659
+ message:
1660
+ "The 'bar' literal is not a valid dependency because it never changes. " +
1661
+ 'Did you mean to include bar in the array instead?',
1662
+ suggestions: undefined,
1663
+ },
1664
],
1665
},
1666
{
1512
- code: `
1667
+ code: normalizeIndent`
1668
function MyComponent({ foo, bar, baz }) {
1669
useEffect(() => {
1670
console.log(foo, bar, baz);
1671
}, [42, false, null]);
1672
}
1673
`,
1519
- output: `
1520
- function MyComponent({ foo, bar, baz }) {
1521
- useEffect(() => {
1522
- console.log(foo, bar, baz);
1523
- }, [bar, baz, foo]);
1524
- }
1525
- `,
1674
errors: [
1527
- "React Hook useEffect has missing dependencies: 'bar', 'baz', and 'foo'. " +
1528
- 'Either include them or remove the dependency array.',
1529
- 'The 42 literal is not a valid dependency because it never changes. You can safely remove it.',
1530
- 'The false literal is not a valid dependency because it never changes. You can safely remove it.',
1531
- 'The null literal is not a valid dependency because it never changes. You can safely remove it.',
1675
+ {
1676
+ message:
1677
+ "React Hook useEffect has missing dependencies: 'bar', 'baz', and 'foo'. " +
1678
+ 'Either include them or remove the dependency array.',
1679
+ suggestions: [
1680
+ {
1681
+ desc: 'Update the dependencies array to be: [bar, baz, foo]',
1682
+ output: normalizeIndent`
1683
+ function MyComponent({ foo, bar, baz }) {
1684
+ useEffect(() => {
1685
+ console.log(foo, bar, baz);
1686
+ }, [bar, baz, foo]);
1687
+ }
1688
+ `,
1689
+ },
1690
+ ],
1691
+ },
1692
+ {
1693
+ message:
1694
+ 'The 42 literal is not a valid dependency because it never changes. You can safely remove it.',
1695
+ suggestions: undefined,
1696
+ },
1697
+ {
1698
+ message:
1699
+ 'The false literal is not a valid dependency because it never changes. You can safely remove it.',
1700
+ suggestions: undefined,
1701
+ },
1702
+ {
1703
+ message:
1704
+ 'The null literal is not a valid dependency because it never changes. You can safely remove it.',
1705
+ suggestions: undefined,
1706
+ },
1707
],
1708
},
1709
{
1535
- code: `
1536
- function MyComponent() {
1537
- const dependencies = [];
1538
- useEffect(() => {}, dependencies);
1539
- }
1540
- `,
1541
- output: `
1710
+ code: normalizeIndent`
1711
function MyComponent() {
1712
const dependencies = [];
1713
useEffect(() => {}, dependencies);
1714
}
1715
`,
1716
errors: [
1548
- 'React Hook useEffect was passed a dependency list that is not an ' +
1549
- "array literal. This means we can't statically verify whether you've " +
1550
- 'passed the correct dependencies.',
1717
+ {
1718
+ message:
1719
+ 'React Hook useEffect was passed a dependency list that is not an ' +
1720
+ "array literal. This means we can't statically verify whether you've " +
1721
+ 'passed the correct dependencies.',
1722
+ suggestions: undefined,
1723
+ },
1724
],
1725
},
1726
{
1554
- code: `
1727
+ code: normalizeIndent`
1728
function MyComponent() {
1729
const local = {};
1730
const dependencies = [local];
@@ -1560,26 +1733,38 @@ const tests = {
1733
}, dependencies);
1734
}
1735
`,
1563
- // TODO: should this autofix or bail out?
1564
- output: `
1565
- function MyComponent() {
1566
- const local = {};
1567
- const dependencies = [local];
1568
- useEffect(() => {
1569
- console.log(local);
1570
- }, [local]);
1571
- }
1572
- `,
1736
errors: [
1574
- 'React Hook useEffect was passed a dependency list that is not an ' +
1575
- "array literal. This means we can't statically verify whether you've " +
1576
- 'passed the correct dependencies.',
1577
- "React Hook useEffect has a missing dependency: 'local'. " +
1578
- 'Either include it or remove the dependency array.',
1737
+ {
1738
+ message:
1739
+ 'React Hook useEffect was passed a dependency list that is not an ' +
1740
+ "array literal. This means we can't statically verify whether you've " +
1741
+ 'passed the correct dependencies.',
1742
+ // TODO: should this autofix or bail out?
1743
+ suggestions: undefined,
1744
+ },
1745
+ {
1746
+ message:
1747
+ "React Hook useEffect has a missing dependency: 'local'. " +
1748
+ 'Either include it or remove the dependency array.',
1749
+ suggestions: [
1750
+ {
1751
+ desc: 'Update the dependencies array to be: [local]',
1752
+ output: normalizeIndent`
1753
+ function MyComponent() {
1754
+ const local = {};
1755
+ const dependencies = [local];
1756
+ useEffect(() => {
1757
+ console.log(local);
1758
+ }, [local]);
1759
+ }
1760
+ `,
1761
+ },
1762
+ ],
1763
+ },
1764
],
1765
},
1766
{
1582
- code: `
1767
+ code: normalizeIndent`
1768
function MyComponent() {
1769
const local = {};
1770
const dependencies = [local];
@@ -1588,34 +1773,38 @@ const tests = {
1773
}, [...dependencies]);
1774
}
1775
`,
1591
- // TODO: should this autofix or bail out?
1592
- output: `
1593
- function MyComponent() {
1594
- const local = {};
1595
- const dependencies = [local];
1596
- useEffect(() => {
1597
- console.log(local);
1598
- }, [local]);
1599
- }
1600
- `,
1776
errors: [
1602
- "React Hook useEffect has a missing dependency: 'local'. " +
1603
- 'Either include it or remove the dependency array.',
1604
- 'React Hook useEffect has a spread element in its dependency array. ' +
1605
- "This means we can't statically verify whether you've passed the " +
1606
- 'correct dependencies.',
1777
+ {
1778
+ message:
1779
+ "React Hook useEffect has a missing dependency: 'local'. " +
1780
+ 'Either include it or remove the dependency array.',
1781
+ suggestions: [
1782
+ {
1783
+ desc: 'Update the dependencies array to be: [local]',
1784
+ output: normalizeIndent`
1785
+ function MyComponent() {
1786
+ const local = {};
1787
+ const dependencies = [local];
1788
+ useEffect(() => {
1789
+ console.log(local);
1790
+ }, [local]);
1791
+ }
1792
+ `,
1793
+ },
1794
+ ],
1795
+ },
1796
+ {
1797
+ message:
1798
+ 'React Hook useEffect has a spread element in its dependency array. ' +
1799
+ "This means we can't statically verify whether you've passed the " +
1800
+ 'correct dependencies.',
1801
+ // TODO: should this autofix or bail out?
1802
+ suggestions: undefined,
1803
+ },
1804
],
1805
},
1806
{
1610
- code: `
1611
- function MyComponent() {
1612
- const local = {};
1613
- useEffect(() => {
1614
- console.log(local);
1615
- }, [local, ...dependencies]);
1616
- }
1617
- `,
1618
- output: `
1807
+ code: normalizeIndent`
1808
function MyComponent() {
1809
const local = {};
1810
useEffect(() => {
@@ -1624,13 +1813,17 @@ const tests = {
1813
}
1814
`,
1815
errors: [
1627
- 'React Hook useEffect has a spread element in its dependency array. ' +
1628
- "This means we can't statically verify whether you've passed the " +
1629
- 'correct dependencies.',
1816
+ {
1817
+ message:
1818
+ 'React Hook useEffect has a spread element in its dependency array. ' +
1819
+ "This means we can't statically verify whether you've passed the " +
1820
+ 'correct dependencies.',
1821
+ suggestions: undefined,
1822
+ },
1823
],
1824
},
1825
{
1633
- code: `
1826
+ code: normalizeIndent`
1827
function MyComponent() {
1828
const local = {};
1829
useEffect(() => {
@@ -1638,55 +1831,71 @@ const tests = {
1831
}, [computeCacheKey(local)]);
1832
}
1833
`,
1641
- // TODO: I'm not sure this is a good idea.
1642
- // Maybe bail out?
1643
- output: `
1644
- function MyComponent() {
1645
- const local = {};
1646
- useEffect(() => {
1647
- console.log(local);
1648
- }, [local]);
1649
- }
1650
- `,
1834
errors: [
1652
- "React Hook useEffect has a missing dependency: 'local'. " +
1653
- 'Either include it or remove the dependency array.',
1654
- 'React Hook useEffect has a complex expression in the dependency array. ' +
1655
- 'Extract it to a separate variable so it can be statically checked.',
1835
+ {
1836
+ message:
1837
+ "React Hook useEffect has a missing dependency: 'local'. " +
1838
+ 'Either include it or remove the dependency array.',
1839
+ // TODO: I'm not sure this is a good idea.
1840
+ // Maybe bail out?
1841
+ suggestions: [
1842
+ {
1843
+ desc: 'Update the dependencies array to be: [local]',
1844
+ output: normalizeIndent`
1845
+ function MyComponent() {
1846
+ const local = {};
1847
+ useEffect(() => {
1848
+ console.log(local);
1849
+ }, [local]);
1850
+ }
1851
+ `,
1852
+ },
1853
+ ],
1854
+ },
1855
+ {
1856
+ message:
1857
+ 'React Hook useEffect has a complex expression in the dependency array. ' +
1858
+ 'Extract it to a separate variable so it can be statically checked.',
1859
+ suggestions: undefined,
1860
+ },
1861
],
1862
},
1863
{
1659
- code: `
1864
+ code: normalizeIndent`
1865
function MyComponent(props) {
1866
useEffect(() => {
1867
console.log(props.items[0]);
1868
}, [props.items[0]]);
1869
}
1870
`,
1666
- output: `
1667
- function MyComponent(props) {
1668
- useEffect(() => {
1669
- console.log(props.items[0]);
1670
- }, [props.items]);
1671
- }
1672
- `,
1871
errors: [
1674
- "React Hook useEffect has a missing dependency: 'props.items'. " +
1675
- 'Either include it or remove the dependency array.',
1676
- 'React Hook useEffect has a complex expression in the dependency array. ' +
1677
- 'Extract it to a separate variable so it can be statically checked.',
1872
+ {
1873
+ message:
1874
+ "React Hook useEffect has a missing dependency: 'props.items'. " +
1875
+ 'Either include it or remove the dependency array.',
1876
+ suggestions: [
1877
+ {
1878
+ desc: 'Update the dependencies array to be: [props.items]',
1879
+ output: normalizeIndent`
1880
+ function MyComponent(props) {
1881
+ useEffect(() => {
1882
+ console.log(props.items[0]);
1883
+ }, [props.items]);
1884
+ }
1885
+ `,
1886
+ },
1887
+ ],
1888
+ },
1889
+ {
1890
+ message:
1891
+ 'React Hook useEffect has a complex expression in the dependency array. ' +
1892
+ 'Extract it to a separate variable so it can be statically checked.',
1893
+ suggestions: undefined,
1894
+ },
1895
],
1896
},
1897
{
1681
- code: `
1682
- function MyComponent(props) {
1683
- useEffect(() => {
1684
- console.log(props.items[0]);
1685
- }, [props.items, props.items[0]]);
1686
- }
1687
- `,
1688
- // TODO: ideally autofix would remove the bad expression?
1689
- output: `
1898
+ code: normalizeIndent`
1899
function MyComponent(props) {
1900
useEffect(() => {
1901
console.log(props.items[0]);
@@ -1694,42 +1903,51 @@ const tests = {
1903
}
1904
`,
1905
errors: [
1697
- 'React Hook useEffect has a complex expression in the dependency array. ' +
1698
- 'Extract it to a separate variable so it can be statically checked.',
1906
+ {
1907
+ message:
1908
+ 'React Hook useEffect has a complex expression in the dependency array. ' +
1909
+ 'Extract it to a separate variable so it can be statically checked.',
1910
+ // TODO: ideally suggestion would remove the bad expression?
1911
+ suggestions: undefined,
1912
+ },
1913
],
1914
},
1915
{
1702
- code: `
1916
+ code: normalizeIndent`
1917
function MyComponent({ items }) {
1918
useEffect(() => {
1919
console.log(items[0]);
1920
}, [items[0]]);
1921
}
1922
`,
1709
- output: `
1710
- function MyComponent({ items }) {
1711
- useEffect(() => {
1712
- console.log(items[0]);
1713
- }, [items]);
1714
- }
1715
- `,
1923
errors: [
1717
- "React Hook useEffect has a missing dependency: 'items'. " +
1718
- 'Either include it or remove the dependency array.',
1719
- 'React Hook useEffect has a complex expression in the dependency array. ' +
1720
- 'Extract it to a separate variable so it can be statically checked.',
1924
+ {
1925
+ message:
1926
+ "React Hook useEffect has a missing dependency: 'items'. " +
1927
+ 'Either include it or remove the dependency array.',
1928
+ suggestions: [
1929
+ {
1930
+ desc: 'Update the dependencies array to be: [items]',
1931
+ output: normalizeIndent`
1932
+ function MyComponent({ items }) {
1933
+ useEffect(() => {
1934
+ console.log(items[0]);
1935
+ }, [items]);
1936
+ }
1937
+ `,
1938
+ },
1939
+ ],
1940
+ },
1941
+ {
1942
+ message:
1943
+ 'React Hook useEffect has a complex expression in the dependency array. ' +
1944
+ 'Extract it to a separate variable so it can be statically checked.',
1945
+ suggestions: undefined,
1946
+ },
1947
],
1948
},
1949
{
1724
- code: `
1725
- function MyComponent({ items }) {
1726
- useEffect(() => {
1727
- console.log(items[0]);
1728
- }, [items, items[0]]);
1729
- }
1730
- `,
1731
- // TODO: ideally autofix would remove the bad expression?
1732
- output: `
1950
+ code: normalizeIndent`
1951
function MyComponent({ items }) {
1952
useEffect(() => {
1953
console.log(items[0]);
@@ -1737,8 +1955,13 @@ const tests = {
1955
}
1956
`,
1957
errors: [
1740
- 'React Hook useEffect has a complex expression in the dependency array. ' +
1741
- 'Extract it to a separate variable so it can be statically checked.',
1958
+ {
1959
+ message:
1960
+ 'React Hook useEffect has a complex expression in the dependency array. ' +
1961
+ 'Extract it to a separate variable so it can be statically checked.',
1962
+ // TODO: ideally suggeston would remove the bad expression?
1963
+ suggestions: undefined,
1964
+ },
1965
],
1966
},
1967
{
@@ -1747,7 +1970,7 @@ const tests = {
1970
// However, we generally allow specifying *broader* deps as escape hatch.
1971
// So while [props, props.foo] is unnecessary, 'props' wins here as the
1972
// broader one, and this is why 'props.foo' is reported as unnecessary.
1750
- code: `
1973
+ code: normalizeIndent`
1974
function MyComponent(props) {
1975
const local = {};
1976
useCallback(() => {
@@ -1756,23 +1979,31 @@ const tests = {
1979
}, [props, props.foo]);
1980
}
1981
`,
1759
- output: `
1760
- function MyComponent(props) {
1761
- const local = {};
1762
- useCallback(() => {
1763
- console.log(props.foo);
1764
- console.log(props.bar);
1765
- }, [props]);
1766
- }
1767
- `,
1982
errors: [
1769
- "React Hook useCallback has an unnecessary dependency: 'props.foo'. " +
1770
- 'Either exclude it or remove the dependency array.',
1983
+ {
1984
+ message:
1985
+ "React Hook useCallback has an unnecessary dependency: 'props.foo'. " +
1986
+ 'Either exclude it or remove the dependency array.',
1987
+ suggestions: [
1988
+ {
1989
+ desc: 'Update the dependencies array to be: [props]',
1990
+ output: normalizeIndent`
1991
+ function MyComponent(props) {
1992
+ const local = {};
1993
+ useCallback(() => {
1994
+ console.log(props.foo);
1995
+ console.log(props.bar);
1996
+ }, [props]);
1997
+ }
1998
+ `,
1999
+ },
2000
+ ],
2001
+ },
2002
],
2003
},
2004
{
2005
// Since we don't have 'props' in the list, we'll suggest narrow dependencies.
1775
- code: `
2006
+ code: normalizeIndent`
2007
function MyComponent(props) {
2008
const local = {};
2009
useCallback(() => {
@@ -1781,24 +2012,33 @@ const tests = {
2012
}, []);
2013
}
2014
`,
1784
- output: `
1785
- function MyComponent(props) {
1786
- const local = {};
1787
- useCallback(() => {
1788
- console.log(props.foo);
1789
- console.log(props.bar);
1790
- }, [props.bar, props.foo]);
1791
- }
1792
- `,
2015
errors: [
1794
- "React Hook useCallback has missing dependencies: 'props.bar' and 'props.foo'. " +
1795
- 'Either include them or remove the dependency array.',
2016
+ {
2017
+ message:
2018
+ "React Hook useCallback has missing dependencies: 'props.bar' and 'props.foo'. " +
2019
+ 'Either include them or remove the dependency array.',
2020
+ suggestions: [
2021
+ {
2022
+ desc:
2023
+ 'Update the dependencies array to be: [props.bar, props.foo]',
2024
+ output: normalizeIndent`
2025
+ function MyComponent(props) {
2026
+ const local = {};
2027
+ useCallback(() => {
2028
+ console.log(props.foo);
2029
+ console.log(props.bar);
2030
+ }, [props.bar, props.foo]);
2031
+ }
2032
+ `,
2033
+ },
2034
+ ],
2035
+ },
2036
],
2037
},
2038
{
2039
// Effects are allowed to over-specify deps. We'll complain about missing
2040
// 'local', but we won't remove the already-specified 'local.id' from your list.
1801
- code: `
2041
+ code: normalizeIndent`
2042
function MyComponent() {
2043
const local = {id: 42};
2044
useEffect(() => {
@@ -1806,23 +2046,31 @@ const tests = {
2046
}, [local.id]);
2047
}
2048
`,
1809
- output: `
1810
- function MyComponent() {
1811
- const local = {id: 42};
1812
- useEffect(() => {
1813
- console.log(local);
1814
- }, [local, local.id]);
1815
- }
1816
- `,
2049
errors: [
1818
- "React Hook useEffect has a missing dependency: 'local'. " +
1819
- 'Either include it or remove the dependency array.',
2050
+ {
2051
+ message:
2052
+ "React Hook useEffect has a missing dependency: 'local'. " +
2053
+ 'Either include it or remove the dependency array.',
2054
+ suggestions: [
2055
+ {
2056
+ desc: 'Update the dependencies array to be: [local, local.id]',
2057
+ output: normalizeIndent`
2058
+ function MyComponent() {
2059
+ const local = {id: 42};
2060
+ useEffect(() => {
2061
+ console.log(local);
2062
+ }, [local, local.id]);
2063
+ }
2064
+ `,
2065
+ },
2066
+ ],
2067
+ },
2068
],
2069
},
2070
{
2071
// Callbacks are not allowed to over-specify deps. So we'll complain about missing
2072
// 'local' and we will also *remove* 'local.id' from your list.
1825
- code: `
2073
+ code: normalizeIndent`
2074
function MyComponent() {
2075
const local = {id: 42};
2076
const fn = useCallback(() => {
@@ -1830,23 +2078,31 @@ const tests = {
2078
}, [local.id]);
2079
}
2080
`,
1833
- output: `
1834
- function MyComponent() {
1835
- const local = {id: 42};
1836
- const fn = useCallback(() => {
1837
- console.log(local);
1838
- }, [local]);
1839
- }
1840
- `,
2081
errors: [
1842
- "React Hook useCallback has a missing dependency: 'local'. " +
1843
- 'Either include it or remove the dependency array.',
2082
+ {
2083
+ message:
2084
+ "React Hook useCallback has a missing dependency: 'local'. " +
2085
+ 'Either include it or remove the dependency array.',
2086
+ suggestions: [
2087
+ {
2088
+ desc: 'Update the dependencies array to be: [local]',
2089
+ output: normalizeIndent`
2090
+ function MyComponent() {
2091
+ const local = {id: 42};
2092
+ const fn = useCallback(() => {
2093
+ console.log(local);
2094
+ }, [local]);
2095
+ }
2096
+ `,
2097
+ },
2098
+ ],
2099
+ },
2100
],
2101
},
2102
{
2103
// Callbacks are not allowed to over-specify deps. So we'll complain about
2104
// the unnecessary 'local.id'.
1849
- code: `
2105
+ code: normalizeIndent`
2106
function MyComponent() {
2107
const local = {id: 42};
2108
const fn = useCallback(() => {
@@ -1854,41 +2110,57 @@ const tests = {
2110
}, [local.id, local]);
2111
}
2112
`,
1857
- output: `
1858
- function MyComponent() {
1859
- const local = {id: 42};
1860
- const fn = useCallback(() => {
1861
- console.log(local);
1862
- }, [local]);
1863
- }
1864
- `,
2113
errors: [
1866
- "React Hook useCallback has an unnecessary dependency: 'local.id'. " +
1867
- 'Either exclude it or remove the dependency array.',
2114
+ {
2115
+ message:
2116
+ "React Hook useCallback has an unnecessary dependency: 'local.id'. " +
2117
+ 'Either exclude it or remove the dependency array.',
2118
+ suggestions: [
2119
+ {
2120
+ desc: 'Update the dependencies array to be: [local]',
2121
+ output: normalizeIndent`
2122
+ function MyComponent() {
2123
+ const local = {id: 42};
2124
+ const fn = useCallback(() => {
2125
+ console.log(local);
2126
+ }, [local]);
2127
+ }
2128
+ `,
2129
+ },
2130
+ ],
2131
+ },
2132
],
2133
},
2134
{
1871
- code: `
2135
+ code: normalizeIndent`
2136
function MyComponent(props) {
2137
const fn = useCallback(() => {
2138
console.log(props.foo.bar.baz);
2139
}, []);
2140
}
2141
`,
1878
- output: `
1879
- function MyComponent(props) {
1880
- const fn = useCallback(() => {
1881
- console.log(props.foo.bar.baz);
1882
- }, [props.foo.bar.baz]);
1883
- }
1884
- `,
2142
errors: [
1886
- "React Hook useCallback has a missing dependency: 'props.foo.bar.baz'. " +
1887
- 'Either include it or remove the dependency array.',
2143
+ {
2144
+ message:
2145
+ "React Hook useCallback has a missing dependency: 'props.foo.bar.baz'. " +
2146
+ 'Either include it or remove the dependency array.',
2147
+ suggestions: [
2148
+ {
2149
+ desc: 'Update the dependencies array to be: [props.foo.bar.baz]',
2150
+ output: normalizeIndent`
2151
+ function MyComponent(props) {
2152
+ const fn = useCallback(() => {
2153
+ console.log(props.foo.bar.baz);
2154
+ }, [props.foo.bar.baz]);
2155
+ }
2156
+ `,
2157
+ },
2158
+ ],
2159
+ },
2160
],
2161
},
2162
{
1891
- code: `
2163
+ code: normalizeIndent`
2164
function MyComponent(props) {
2165
let color = {}
2166
const fn = useCallback(() => {
@@ -1897,18 +2169,27 @@ const tests = {
2169
}, [props.foo, props.foo.bar.baz]);
2170
}
2171
`,
1900
- output: `
1901
- function MyComponent(props) {
1902
- let color = {}
1903
- const fn = useCallback(() => {
1904
- console.log(props.foo.bar.baz);
1905
- console.log(color);
1906
- }, [color, props.foo.bar.baz]);
1907
- }
1908
- `,
2172
errors: [
1910
- "React Hook useCallback has a missing dependency: 'color'. " +
1911
- 'Either include it or remove the dependency array.',
2173
+ {
2174
+ message:
2175
+ "React Hook useCallback has a missing dependency: 'color'. " +
2176
+ 'Either include it or remove the dependency array.',
2177
+ suggestions: [
2178
+ {
2179
+ desc:
2180
+ 'Update the dependencies array to be: [color, props.foo.bar.baz]',
2181
+ output: normalizeIndent`
2182
+ function MyComponent(props) {
2183
+ let color = {}
2184
+ const fn = useCallback(() => {
2185
+ console.log(props.foo.bar.baz);
2186
+ console.log(color);
2187
+ }, [color, props.foo.bar.baz]);
2188
+ }
2189
+ `,
2190
+ },
2191
+ ],
2192
+ },
2193
],
2194
},
2195
{
@@ -1917,27 +2198,35 @@ const tests = {
2198
// So in this case we ask you to remove 'props.foo.bar.baz' because 'props.foo'
2199
// already covers it, and having both is unnecessary.
2200
// TODO: maybe consider suggesting a narrower one by default in these cases.
1920
- code: `
2201
+ code: normalizeIndent`
2202
function MyComponent(props) {
2203
const fn = useCallback(() => {
2204
console.log(props.foo.bar.baz);
2205
}, [props.foo.bar.baz, props.foo]);
2206
}
2207
`,
1927
- output: `
1928
- function MyComponent(props) {
1929
- const fn = useCallback(() => {
1930
- console.log(props.foo.bar.baz);
1931
- }, [props.foo]);
1932
- }
1933
- `,
2208
errors: [
1935
- "React Hook useCallback has an unnecessary dependency: 'props.foo.bar.baz'. " +
1936
- 'Either exclude it or remove the dependency array.',
2209
+ {
2210
+ message:
2211
+ "React Hook useCallback has an unnecessary dependency: 'props.foo.bar.baz'. " +
2212
+ 'Either exclude it or remove the dependency array.',
2213
+ suggestions: [
2214
+ {
2215
+ desc: 'Update the dependencies array to be: [props.foo]',
2216
+ output: normalizeIndent`
2217
+ function MyComponent(props) {
2218
+ const fn = useCallback(() => {
2219
+ console.log(props.foo.bar.baz);
2220
+ }, [props.foo]);
2221
+ }
2222
+ `,
2223
+ },
2224
+ ],
2225
+ },
2226
],
2227
},
2228
{
1940
- code: `
2229
+ code: normalizeIndent`
2230
function MyComponent(props) {
2231
const fn = useCallback(() => {
2232
console.log(props.foo.bar.baz);
@@ -1945,17 +2234,26 @@ const tests = {
2234
}, []);
2235
}
2236
`,
1948
- output: `
1949
- function MyComponent(props) {
1950
- const fn = useCallback(() => {
1951
- console.log(props.foo.bar.baz);
1952
- console.log(props.foo.fizz.bizz);
1953
- }, [props.foo.bar.baz, props.foo.fizz.bizz]);
1954
- }
1955
- `,
2237
errors: [
1957
- "React Hook useCallback has missing dependencies: 'props.foo.bar.baz' and 'props.foo.fizz.bizz'. " +
1958
- 'Either include them or remove the dependency array.',
2238
+ {
2239
+ message:
2240
+ "React Hook useCallback has missing dependencies: 'props.foo.bar.baz' and 'props.foo.fizz.bizz'. " +
2241
+ 'Either include them or remove the dependency array.',
2242
+ suggestions: [
2243
+ {
2244
+ desc:
2245
+ 'Update the dependencies array to be: [props.foo.bar.baz, props.foo.fizz.bizz]',
2246
+ output: normalizeIndent`
2247
+ function MyComponent(props) {
2248
+ const fn = useCallback(() => {
2249
+ console.log(props.foo.bar.baz);
2250
+ console.log(props.foo.fizz.bizz);
2251
+ }, [props.foo.bar.baz, props.foo.fizz.bizz]);
2252
+ }
2253
+ `,
2254
+ },
2255
+ ],
2256
+ },
2257
],
2258
},
2259
{
@@ -1965,27 +2263,35 @@ const tests = {
2263
// When we're sure there is a mistake, for callbacks we will rebuild the list
2264
// from scratch. This will set the user on a better path by default.
2265
// This is why we end up with just 'props.foo.bar', and not them both.
1968
- code: `
2266
+ code: normalizeIndent`
2267
function MyComponent(props) {
2268
const fn = useCallback(() => {
2269
console.log(props.foo.bar);
2270
}, [props.foo.bar.baz]);
2271
}
2272
`,
1975
- output: `
1976
- function MyComponent(props) {
1977
- const fn = useCallback(() => {
1978
- console.log(props.foo.bar);
1979
- }, [props.foo.bar]);
1980
- }
1981
- `,
2273
errors: [
1983
- "React Hook useCallback has a missing dependency: 'props.foo.bar'. " +
1984
- 'Either include it or remove the dependency array.',
2274
+ {
2275
+ message:
2276
+ "React Hook useCallback has a missing dependency: 'props.foo.bar'. " +
2277
+ 'Either include it or remove the dependency array.',
2278
+ suggestions: [
2279
+ {
2280
+ desc: 'Update the dependencies array to be: [props.foo.bar]',
2281
+ output: normalizeIndent`
2282
+ function MyComponent(props) {
2283
+ const fn = useCallback(() => {
2284
+ console.log(props.foo.bar);
2285
+ }, [props.foo.bar]);
2286
+ }
2287
+ `,
2288
+ },
2289
+ ],
2290
+ },
2291
],
2292
},
2293
{
1988
- code: `
2294
+ code: normalizeIndent`
2295
function MyComponent(props) {
2296
const fn = useCallback(() => {
2297
console.log(props);
@@ -1993,21 +2299,29 @@ const tests = {
2299
}, [props.foo.bar.baz]);
2300
}
2301
`,
1996
- output: `
1997
- function MyComponent(props) {
1998
- const fn = useCallback(() => {
1999
- console.log(props);
2000
- console.log(props.hello);
2001
- }, [props]);
2002
- }
2003
- `,
2302
errors: [
2005
- "React Hook useCallback has a missing dependency: 'props'. " +
2006
- 'Either include it or remove the dependency array.',
2303
+ {
2304
+ message:
2305
+ "React Hook useCallback has a missing dependency: 'props'. " +
2306
+ 'Either include it or remove the dependency array.',
2307
+ suggestions: [
2308
+ {
2309
+ desc: 'Update the dependencies array to be: [props]',
2310
+ output: normalizeIndent`
2311
+ function MyComponent(props) {
2312
+ const fn = useCallback(() => {
2313
+ console.log(props);
2314
+ console.log(props.hello);
2315
+ }, [props]);
2316
+ }
2317
+ `,
2318
+ },
2319
+ ],
2320
+ },
2321
],
2322
},
2323
{
2010
- code: `
2324
+ code: normalizeIndent`
2325
function MyComponent() {
2326
const local = {};
2327
useEffect(() => {
@@ -2015,21 +2329,29 @@ const tests = {
2329
}, [local, local]);
2330
}
2331
`,
2018
- output: `
2019
- function MyComponent() {
2020
- const local = {};
2021
- useEffect(() => {
2022
- console.log(local);
2023
- }, [local]);
2024
- }
2025
- `,
2332
errors: [
2027
- "React Hook useEffect has a duplicate dependency: 'local'. " +
2028
- 'Either omit it or remove the dependency array.',
2333
+ {
2334
+ message:
2335
+ "React Hook useEffect has a duplicate dependency: 'local'. " +
2336
+ 'Either omit it or remove the dependency array.',
2337
+ suggestions: [
2338
+ {
2339
+ desc: 'Update the dependencies array to be: [local]',
2340
+ output: normalizeIndent`
2341
+ function MyComponent() {
2342
+ const local = {};
2343
+ useEffect(() => {
2344
+ console.log(local);
2345
+ }, [local]);
2346
+ }
2347
+ `,
2348
+ },
2349
+ ],
2350
+ },
2351
],
2352
},
2353
{
2032
- code: `
2354
+ code: normalizeIndent`
2355
function MyComponent() {
2356
const local1 = {};
2357
useCallback(() => {
@@ -2038,60 +2360,84 @@ const tests = {
2360
}, [local1]);
2361
}
2362
`,
2041
- output: `
2042
- function MyComponent() {
2043
- const local1 = {};
2044
- useCallback(() => {
2045
- const local1 = {};
2046
- console.log(local1);
2047
- }, []);
2048
- }
2049
- `,
2363
errors: [
2051
- "React Hook useCallback has an unnecessary dependency: 'local1'. " +
2052
- 'Either exclude it or remove the dependency array.',
2364
+ {
2365
+ message:
2366
+ "React Hook useCallback has an unnecessary dependency: 'local1'. " +
2367
+ 'Either exclude it or remove the dependency array.',
2368
+ suggestions: [
2369
+ {
2370
+ desc: 'Update the dependencies array to be: []',
2371
+ output: normalizeIndent`
2372
+ function MyComponent() {
2373
+ const local1 = {};
2374
+ useCallback(() => {
2375
+ const local1 = {};
2376
+ console.log(local1);
2377
+ }, []);
2378
+ }
2379
+ `,
2380
+ },
2381
+ ],
2382
+ },
2383
],
2384
},
2385
{
2056
- code: `
2386
+ code: normalizeIndent`
2387
function MyComponent() {
2388
const local1 = {};
2389
useCallback(() => {}, [local1]);
2390
}
2391
`,
2062
- output: `
2063
- function MyComponent() {
2064
- const local1 = {};
2065
- useCallback(() => {}, []);
2066
- }
2067
- `,
2392
errors: [
2069
- "React Hook useCallback has an unnecessary dependency: 'local1'. " +
2070
- 'Either exclude it or remove the dependency array.',
2393
+ {
2394
+ message:
2395
+ "React Hook useCallback has an unnecessary dependency: 'local1'. " +
2396
+ 'Either exclude it or remove the dependency array.',
2397
+ suggestions: [
2398
+ {
2399
+ desc: 'Update the dependencies array to be: []',
2400
+ output: normalizeIndent`
2401
+ function MyComponent() {
2402
+ const local1 = {};
2403
+ useCallback(() => {}, []);
2404
+ }
2405
+ `,
2406
+ },
2407
+ ],
2408
+ },
2409
],
2410
},
2411
{
2074
- code: `
2412
+ code: normalizeIndent`
2413
function MyComponent(props) {
2414
useEffect(() => {
2415
console.log(props.foo);
2416
}, []);
2417
}
2418
`,
2081
- output: `
2082
- function MyComponent(props) {
2083
- useEffect(() => {
2084
- console.log(props.foo);
2085
- }, [props.foo]);
2086
- }
2087
- `,
2088
- errors: [
2089
- "React Hook useEffect has a missing dependency: 'props.foo'. " +
2090
- 'Either include it or remove the dependency array.',
2091
- ],
2092
- },
2093
- {
2094
- code: `
2419
+ errors: [
2420
+ {
2421
+ message:
2422
+ "React Hook useEffect has a missing dependency: 'props.foo'. " +
2423
+ 'Either include it or remove the dependency array.',
2424
+ suggestions: [
2425
+ {
2426
+ desc: 'Update the dependencies array to be: [props.foo]',
2427
+ output: normalizeIndent`
2428
+ function MyComponent(props) {
2429
+ useEffect(() => {
2430
+ console.log(props.foo);
2431
+ }, [props.foo]);
2432
+ }
2433
+ `,
2434
+ },
2435
+ ],
2436
+ },
2437
+ ],
2438
+ },
2439
+ {
2440
+ code: normalizeIndent`
2441
function MyComponent(props) {
2442
useEffect(() => {
2443
console.log(props.foo);
@@ -2099,21 +2445,30 @@ const tests = {
2445
}, []);
2446
}
2447
`,
2102
- output: `
2103
- function MyComponent(props) {
2104
- useEffect(() => {
2105
- console.log(props.foo);
2106
- console.log(props.bar);
2107
- }, [props.bar, props.foo]);
2108
- }
2109
- `,
2448
errors: [
2111
- "React Hook useEffect has missing dependencies: 'props.bar' and 'props.foo'. " +
2112
- 'Either include them or remove the dependency array.',
2449
+ {
2450
+ message:
2451
+ "React Hook useEffect has missing dependencies: 'props.bar' and 'props.foo'. " +
2452
+ 'Either include them or remove the dependency array.',
2453
+ suggestions: [
2454
+ {
2455
+ desc:
2456
+ 'Update the dependencies array to be: [props.bar, props.foo]',
2457
+ output: normalizeIndent`
2458
+ function MyComponent(props) {
2459
+ useEffect(() => {
2460
+ console.log(props.foo);
2461
+ console.log(props.bar);
2462
+ }, [props.bar, props.foo]);
2463
+ }
2464
+ `,
2465
+ },
2466
+ ],
2467
+ },
2468
],
2469
},
2470
{
2116
- code: `
2471
+ code: normalizeIndent`
2472
function MyComponent(props) {
2473
let a, b, c, d, e, f, g;
2474
useEffect(() => {
@@ -2121,22 +2476,31 @@ const tests = {
2476
}, [c, a, g]);
2477
}
2478
`,
2124
- // Don't alphabetize if it wasn't alphabetized in the first place.
2125
- output: `
2126
- function MyComponent(props) {
2127
- let a, b, c, d, e, f, g;
2128
- useEffect(() => {
2129
- console.log(b, e, d, c, a, g, f);
2130
- }, [c, a, g, b, e, d, f]);
2131
- }
2132
- `,
2479
errors: [
2134
- "React Hook useEffect has missing dependencies: 'b', 'd', 'e', and 'f'. " +
2135
- 'Either include them or remove the dependency array.',
2480
+ {
2481
+ message:
2482
+ "React Hook useEffect has missing dependencies: 'b', 'd', 'e', and 'f'. " +
2483
+ 'Either include them or remove the dependency array.',
2484
+ // Don't alphabetize if it wasn't alphabetized in the first place.
2485
+ suggestions: [
2486
+ {
2487
+ desc:
2488
+ 'Update the dependencies array to be: [c, a, g, b, e, d, f]',
2489
+ output: normalizeIndent`
2490
+ function MyComponent(props) {
2491
+ let a, b, c, d, e, f, g;
2492
+ useEffect(() => {
2493
+ console.log(b, e, d, c, a, g, f);
2494
+ }, [c, a, g, b, e, d, f]);
2495
+ }
2496
+ `,
2497
+ },
2498
+ ],
2499
+ },
2500
],
2501
},
2502
{
2139
- code: `
2503
+ code: normalizeIndent`
2504
function MyComponent(props) {
2505
let a, b, c, d, e, f, g;
2506
useEffect(() => {
@@ -2144,22 +2508,31 @@ const tests = {
2508
}, [a, c, g]);
2509
}
2510
`,
2147
- // Alphabetize if it was alphabetized.
2148
- output: `
2149
- function MyComponent(props) {
2150
- let a, b, c, d, e, f, g;
2151
- useEffect(() => {
2152
- console.log(b, e, d, c, a, g, f);
2153
- }, [a, b, c, d, e, f, g]);
2154
- }
2155
- `,
2511
errors: [
2157
- "React Hook useEffect has missing dependencies: 'b', 'd', 'e', and 'f'. " +
2158
- 'Either include them or remove the dependency array.',
2512
+ {
2513
+ message:
2514
+ "React Hook useEffect has missing dependencies: 'b', 'd', 'e', and 'f'. " +
2515
+ 'Either include them or remove the dependency array.',
2516
+ // Alphabetize if it was alphabetized.
2517
+ suggestions: [
2518
+ {
2519
+ desc:
2520
+ 'Update the dependencies array to be: [a, b, c, d, e, f, g]',
2521
+ output: normalizeIndent`
2522
+ function MyComponent(props) {
2523
+ let a, b, c, d, e, f, g;
2524
+ useEffect(() => {
2525
+ console.log(b, e, d, c, a, g, f);
2526
+ }, [a, b, c, d, e, f, g]);
2527
+ }
2528
+ `,
2529
+ },
2530
+ ],
2531
+ },
2532
],
2533
},
2534
{
2162
- code: `
2535
+ code: normalizeIndent`
2536
function MyComponent(props) {
2537
let a, b, c, d, e, f, g;
2538
useEffect(() => {
@@ -2167,22 +2540,31 @@ const tests = {
2540
}, []);
2541
}
2542
`,
2170
- // Alphabetize if it was empty.
2171
- output: `
2172
- function MyComponent(props) {
2173
- let a, b, c, d, e, f, g;
2174
- useEffect(() => {
2175
- console.log(b, e, d, c, a, g, f);
2176
- }, [a, b, c, d, e, f, g]);
2177
- }
2178
- `,
2543
errors: [
2180
- "React Hook useEffect has missing dependencies: 'a', 'b', 'c', 'd', 'e', 'f', and 'g'. " +
2181
- 'Either include them or remove the dependency array.',
2544
+ {
2545
+ message:
2546
+ "React Hook useEffect has missing dependencies: 'a', 'b', 'c', 'd', 'e', 'f', and 'g'. " +
2547
+ 'Either include them or remove the dependency array.',
2548
+ // Alphabetize if it was empty.
2549
+ suggestions: [
2550
+ {
2551
+ desc:
2552
+ 'Update the dependencies array to be: [a, b, c, d, e, f, g]',
2553
+ output: normalizeIndent`
2554
+ function MyComponent(props) {
2555
+ let a, b, c, d, e, f, g;
2556
+ useEffect(() => {
2557
+ console.log(b, e, d, c, a, g, f);
2558
+ }, [a, b, c, d, e, f, g]);
2559
+ }
2560
+ `,
2561
+ },
2562
+ ],
2563
+ },
2564
],
2565
},
2566
{
2185
- code: `
2567
+ code: normalizeIndent`
2568
function MyComponent(props) {
2569
const local = {};
2570
useEffect(() => {
@@ -2192,23 +2574,32 @@ const tests = {
2574
}, []);
2575
}
2576
`,
2195
- output: `
2196
- function MyComponent(props) {
2197
- const local = {};
2198
- useEffect(() => {
2199
- console.log(props.foo);
2200
- console.log(props.bar);
2201
- console.log(local);
2202
- }, [local, props.bar, props.foo]);
2203
- }
2204
- `,
2577
errors: [
2206
- "React Hook useEffect has missing dependencies: 'local', 'props.bar', and 'props.foo'. " +
2207
- 'Either include them or remove the dependency array.',
2578
+ {
2579
+ message:
2580
+ "React Hook useEffect has missing dependencies: 'local', 'props.bar', and 'props.foo'. " +
2581
+ 'Either include them or remove the dependency array.',
2582
+ suggestions: [
2583
+ {
2584
+ desc:
2585
+ 'Update the dependencies array to be: [local, props.bar, props.foo]',
2586
+ output: normalizeIndent`
2587
+ function MyComponent(props) {
2588
+ const local = {};
2589
+ useEffect(() => {
2590
+ console.log(props.foo);
2591
+ console.log(props.bar);
2592
+ console.log(local);
2593
+ }, [local, props.bar, props.foo]);
2594
+ }
2595
+ `,
2596
+ },
2597
+ ],
2598
+ },
2599
],
2600
},
2601
{
2211
- code: `
2602
+ code: normalizeIndent`
2603
function MyComponent(props) {
2604
const local = {};
2605
useEffect(() => {
@@ -2218,23 +2609,31 @@ const tests = {
2609
}, [props]);
2610
}
2611
`,
2221
- output: `
2222
- function MyComponent(props) {
2223
- const local = {};
2224
- useEffect(() => {
2225
- console.log(props.foo);
2226
- console.log(props.bar);
2227
- console.log(local);
2228
- }, [local, props]);
2229
- }
2230
- `,
2612
errors: [
2232
- "React Hook useEffect has a missing dependency: 'local'. " +
2233
- 'Either include it or remove the dependency array.',
2613
+ {
2614
+ message:
2615
+ "React Hook useEffect has a missing dependency: 'local'. " +
2616
+ 'Either include it or remove the dependency array.',
2617
+ suggestions: [
2618
+ {
2619
+ desc: 'Update the dependencies array to be: [local, props]',
2620
+ output: normalizeIndent`
2621
+ function MyComponent(props) {
2622
+ const local = {};
2623
+ useEffect(() => {
2624
+ console.log(props.foo);
2625
+ console.log(props.bar);
2626
+ console.log(local);
2627
+ }, [local, props]);
2628
+ }
2629
+ `,
2630
+ },
2631
+ ],
2632
+ },
2633
],
2634
},
2635
{
2237
- code: `
2636
+ code: normalizeIndent`
2637
function MyComponent(props) {
2638
useEffect(() => {
2639
console.log(props.foo);
@@ -2259,48 +2658,221 @@ const tests = {
2658
}, []);
2659
}
2660
`,
2262
- output: `
2263
- function MyComponent(props) {
2264
- useEffect(() => {
2265
- console.log(props.foo);
2266
- }, [props.foo]);
2267
- useCallback(() => {
2268
- console.log(props.foo);
2269
- }, [props.foo]);
2270
- useMemo(() => {
2271
- console.log(props.foo);
2272
- }, [props.foo]);
2273
- React.useEffect(() => {
2274
- console.log(props.foo);
2275
- }, [props.foo]);
2276
- React.useCallback(() => {
2277
- console.log(props.foo);
2278
- }, [props.foo]);
2279
- React.useMemo(() => {
2280
- console.log(props.foo);
2281
- }, [props.foo]);
2282
- React.notReactiveHook(() => {
2283
- console.log(props.foo);
2284
- }, []);
2285
- }
2286
- `,
2661
errors: [
2288
- "React Hook useEffect has a missing dependency: 'props.foo'. " +
2289
- 'Either include it or remove the dependency array.',
2290
- "React Hook useCallback has a missing dependency: 'props.foo'. " +
2291
- 'Either include it or remove the dependency array.',
2292
- "React Hook useMemo has a missing dependency: 'props.foo'. " +
2293
- 'Either include it or remove the dependency array.',
2294
- "React Hook React.useEffect has a missing dependency: 'props.foo'. " +
2295
- 'Either include it or remove the dependency array.',
2296
- "React Hook React.useCallback has a missing dependency: 'props.foo'. " +
2297
- 'Either include it or remove the dependency array.',
2298
- "React Hook React.useMemo has a missing dependency: 'props.foo'. " +
2299
- 'Either include it or remove the dependency array.',
2662
+ {
2663
+ message:
2664
+ "React Hook useEffect has a missing dependency: 'props.foo'. " +
2665
+ 'Either include it or remove the dependency array.',
2666
+ suggestions: [
2667
+ {
2668
+ desc: 'Update the dependencies array to be: [props.foo]',
2669
+ output: normalizeIndent`
2670
+ function MyComponent(props) {
2671
+ useEffect(() => {
2672
+ console.log(props.foo);
2673
+ }, [props.foo]);
2674
+ useCallback(() => {
2675
+ console.log(props.foo);
2676
+ }, []);
2677
+ useMemo(() => {
2678
+ console.log(props.foo);
2679
+ }, []);
2680
+ React.useEffect(() => {
2681
+ console.log(props.foo);
2682
+ }, []);
2683
+ React.useCallback(() => {
2684
+ console.log(props.foo);
2685
+ }, []);
2686
+ React.useMemo(() => {
2687
+ console.log(props.foo);
2688
+ }, []);
2689
+ React.notReactiveHook(() => {
2690
+ console.log(props.foo);
2691
+ }, []);
2692
+ }
2693
+ `,
2694
+ },
2695
+ ],
2696
+ },
2697
+ {
2698
+ message:
2699
+ "React Hook useCallback has a missing dependency: 'props.foo'. " +
2700
+ 'Either include it or remove the dependency array.',
2701
+ suggestions: [
2702
+ {
2703
+ desc: 'Update the dependencies array to be: [props.foo]',
2704
+ output: normalizeIndent`
2705
+ function MyComponent(props) {
2706
+ useEffect(() => {
2707
+ console.log(props.foo);
2708
+ }, []);
2709
+ useCallback(() => {
2710
+ console.log(props.foo);
2711
+ }, [props.foo]);
2712
+ useMemo(() => {
2713
+ console.log(props.foo);
2714
+ }, []);
2715
+ React.useEffect(() => {
2716
+ console.log(props.foo);
2717
+ }, []);
2718
+ React.useCallback(() => {
2719
+ console.log(props.foo);
2720
+ }, []);
2721
+ React.useMemo(() => {
2722
+ console.log(props.foo);
2723
+ }, []);
2724
+ React.notReactiveHook(() => {
2725
+ console.log(props.foo);
2726
+ }, []);
2727
+ }
2728
+ `,
2729
+ },
2730
+ ],
2731
+ },
2732
+ {
2733
+ message:
2734
+ "React Hook useMemo has a missing dependency: 'props.foo'. " +
2735
+ 'Either include it or remove the dependency array.',
2736
+ suggestions: [
2737
+ {
2738
+ desc: 'Update the dependencies array to be: [props.foo]',
2739
+ output: normalizeIndent`
2740
+ function MyComponent(props) {
2741
+ useEffect(() => {
2742
+ console.log(props.foo);
2743
+ }, []);
2744
+ useCallback(() => {
2745
+ console.log(props.foo);
2746
+ }, []);
2747
+ useMemo(() => {
2748
+ console.log(props.foo);
2749
+ }, [props.foo]);
2750
+ React.useEffect(() => {
2751
+ console.log(props.foo);
2752
+ }, []);
2753
+ React.useCallback(() => {
2754
+ console.log(props.foo);
2755
+ }, []);
2756
+ React.useMemo(() => {
2757
+ console.log(props.foo);
2758
+ }, []);
2759
+ React.notReactiveHook(() => {
2760
+ console.log(props.foo);
2761
+ }, []);
2762
+ }
2763
+ `,
2764
+ },
2765
+ ],
2766
+ },
2767
+ {
2768
+ message:
2769
+ "React Hook React.useEffect has a missing dependency: 'props.foo'. " +
2770
+ 'Either include it or remove the dependency array.',
2771
+ suggestions: [
2772
+ {
2773
+ desc: 'Update the dependencies array to be: [props.foo]',
2774
+ output: normalizeIndent`
2775
+ function MyComponent(props) {
2776
+ useEffect(() => {
2777
+ console.log(props.foo);
2778
+ }, []);
2779
+ useCallback(() => {
2780
+ console.log(props.foo);
2781
+ }, []);
2782
+ useMemo(() => {
2783
+ console.log(props.foo);
2784
+ }, []);
2785
+ React.useEffect(() => {
2786
+ console.log(props.foo);
2787
+ }, [props.foo]);
2788
+ React.useCallback(() => {
2789
+ console.log(props.foo);
2790
+ }, []);
2791
+ React.useMemo(() => {
2792
+ console.log(props.foo);
2793
+ }, []);
2794
+ React.notReactiveHook(() => {
2795
+ console.log(props.foo);
2796
+ }, []);
2797
+ }
2798
+ `,
2799
+ },
2800
+ ],
2801
+ },
2802
+ {
2803
+ message:
2804
+ "React Hook React.useCallback has a missing dependency: 'props.foo'. " +
2805
+ 'Either include it or remove the dependency array.',
2806
+ suggestions: [
2807
+ {
2808
+ desc: 'Update the dependencies array to be: [props.foo]',
2809
+ output: normalizeIndent`
2810
+ function MyComponent(props) {
2811
+ useEffect(() => {
2812
+ console.log(props.foo);
2813
+ }, []);
2814
+ useCallback(() => {
2815
+ console.log(props.foo);
2816
+ }, []);
2817
+ useMemo(() => {
2818
+ console.log(props.foo);
2819
+ }, []);
2820
+ React.useEffect(() => {
2821
+ console.log(props.foo);
2822
+ }, []);
2823
+ React.useCallback(() => {
2824
+ console.log(props.foo);
2825
+ }, [props.foo]);
2826
+ React.useMemo(() => {
2827
+ console.log(props.foo);
2828
+ }, []);
2829
+ React.notReactiveHook(() => {
2830
+ console.log(props.foo);
2831
+ }, []);
2832
+ }
2833
+ `,
2834
+ },
2835
+ ],
2836
+ },
2837
+ {
2838
+ message:
2839
+ "React Hook React.useMemo has a missing dependency: 'props.foo'. " +
2840
+ 'Either include it or remove the dependency array.',
2841
+ suggestions: [
2842
+ {
2843
+ desc: 'Update the dependencies array to be: [props.foo]',
2844
+ output: normalizeIndent`
2845
+ function MyComponent(props) {
2846
+ useEffect(() => {
2847
+ console.log(props.foo);
2848
+ }, []);
2849
+ useCallback(() => {
2850
+ console.log(props.foo);
2851
+ }, []);
2852
+ useMemo(() => {
2853
+ console.log(props.foo);
2854
+ }, []);
2855
+ React.useEffect(() => {
2856
+ console.log(props.foo);
2857
+ }, []);
2858
+ React.useCallback(() => {
2859
+ console.log(props.foo);
2860
+ }, []);
2861
+ React.useMemo(() => {
2862
+ console.log(props.foo);
2863
+ }, [props.foo]);
2864
+ React.notReactiveHook(() => {
2865
+ console.log(props.foo);
2866
+ }, []);
2867
+ }
2868
+ `,
2869
+ },
2870
+ ],
2871
+ },
2872
],
2873
},
2874
{
2303
- code: `
2875
+ code: normalizeIndent`
2876
function MyComponent(props) {
2877
useCustomEffect(() => {
2878
console.log(props.foo);
@@ -2316,34 +2888,90 @@ const tests = {
2888
}, []);
2889
}
2890
`,
2319
- output: `
2320
- function MyComponent(props) {
2321
- useCustomEffect(() => {
2322
- console.log(props.foo);
2323
- }, [props.foo]);
2324
- useEffect(() => {
2325
- console.log(props.foo);
2326
- }, [props.foo]);
2327
- React.useEffect(() => {
2328
- console.log(props.foo);
2329
- }, [props.foo]);
2330
- React.useCustomEffect(() => {
2331
- console.log(props.foo);
2332
- }, []);
2333
- }
2334
- `,
2891
options: [{additionalHooks: 'useCustomEffect'}],
2892
errors: [
2337
- "React Hook useCustomEffect has a missing dependency: 'props.foo'. " +
2338
- 'Either include it or remove the dependency array.',
2339
- "React Hook useEffect has a missing dependency: 'props.foo'. " +
2340
- 'Either include it or remove the dependency array.',
2341
- "React Hook React.useEffect has a missing dependency: 'props.foo'. " +
2342
- 'Either include it or remove the dependency array.',
2893
+ {
2894
+ message:
2895
+ "React Hook useCustomEffect has a missing dependency: 'props.foo'. " +
2896
+ 'Either include it or remove the dependency array.',
2897
+ suggestions: [
2898
+ {
2899
+ desc: 'Update the dependencies array to be: [props.foo]',
2900
+ output: normalizeIndent`
2901
+ function MyComponent(props) {
2902
+ useCustomEffect(() => {
2903
+ console.log(props.foo);
2904
+ }, [props.foo]);
2905
+ useEffect(() => {
2906
+ console.log(props.foo);
2907
+ }, []);
2908
+ React.useEffect(() => {
2909
+ console.log(props.foo);
2910
+ }, []);
2911
+ React.useCustomEffect(() => {
2912
+ console.log(props.foo);
2913
+ }, []);
2914
+ }
2915
+ `,
2916
+ },
2917
+ ],
2918
+ },
2919
+ {
2920
+ message:
2921
+ "React Hook useEffect has a missing dependency: 'props.foo'. " +
2922
+ 'Either include it or remove the dependency array.',
2923
+ suggestions: [
2924
+ {
2925
+ desc: 'Update the dependencies array to be: [props.foo]',
2926
+ output: normalizeIndent`
2927
+ function MyComponent(props) {
2928
+ useCustomEffect(() => {
2929
+ console.log(props.foo);
2930
+ }, []);
2931
+ useEffect(() => {
2932
+ console.log(props.foo);
2933
+ }, [props.foo]);
2934
+ React.useEffect(() => {
2935
+ console.log(props.foo);
2936
+ }, []);
2937
+ React.useCustomEffect(() => {
2938
+ console.log(props.foo);
2939
+ }, []);
2940
+ }
2941
+ `,
2942
+ },
2943
+ ],
2944
+ },
2945
+ {
2946
+ message:
2947
+ "React Hook React.useEffect has a missing dependency: 'props.foo'. " +
2948
+ 'Either include it or remove the dependency array.',
2949
+ suggestions: [
2950
+ {
2951
+ desc: 'Update the dependencies array to be: [props.foo]',
2952
+ output: normalizeIndent`
2953
+ function MyComponent(props) {
2954
+ useCustomEffect(() => {
2955
+ console.log(props.foo);
2956
+ }, []);
2957
+ useEffect(() => {
2958
+ console.log(props.foo);
2959
+ }, []);
2960
+ React.useEffect(() => {
2961
+ console.log(props.foo);
2962
+ }, [props.foo]);
2963
+ React.useCustomEffect(() => {
2964
+ console.log(props.foo);
2965
+ }, []);
2966
+ }
2967
+ `,
2968
+ },
2969
+ ],
2970
+ },
2971
],
2972
},
2973
{
2346
- code: `
2974
+ code: normalizeIndent`
2975
function MyComponent() {
2976
const local = {};
2977
useEffect(() => {
@@ -2351,24 +2979,36 @@ const tests = {
2979
}, [a ? local : b]);
2980
}
2981
`,
2354
- // TODO: should we bail out instead?
2355
- output: `
2356
- function MyComponent() {
2357
- const local = {};
2358
- useEffect(() => {
2359
- console.log(local);
2360
- }, [local]);
2361
- }
2362
- `,
2982
errors: [
2364
- "React Hook useEffect has a missing dependency: 'local'. " +
2365
- 'Either include it or remove the dependency array.',
2366
- 'React Hook useEffect has a complex expression in the dependency array. ' +
2367
- 'Extract it to a separate variable so it can be statically checked.',
2983
+ {
2984
+ message:
2985
+ "React Hook useEffect has a missing dependency: 'local'. " +
2986
+ 'Either include it or remove the dependency array.',
2987
+ // TODO: should we bail out instead?
2988
+ suggestions: [
2989
+ {
2990
+ desc: 'Update the dependencies array to be: [local]',
2991
+ output: normalizeIndent`
2992
+ function MyComponent() {
2993
+ const local = {};
2994
+ useEffect(() => {
2995
+ console.log(local);
2996
+ }, [local]);
2997
+ }
2998
+ `,
2999
+ },
3000
+ ],
3001
+ },
3002
+ {
3003
+ message:
3004
+ 'React Hook useEffect has a complex expression in the dependency array. ' +
3005
+ 'Extract it to a separate variable so it can be statically checked.',
3006
+ suggestions: undefined,
3007
+ },
3008
],
3009
},
3010
{
2371
- code: `
3011
+ code: normalizeIndent`
3012
function MyComponent() {
3013
const local = {};
3014
useEffect(() => {
@@ -2376,24 +3016,36 @@ const tests = {
3016
}, [a && local]);
3017
}
3018
`,
2379
- // TODO: should we bail out instead?
2380
- output: `
2381
- function MyComponent() {
2382
- const local = {};
2383
- useEffect(() => {
2384
- console.log(local);
2385
- }, [local]);
2386
- }
2387
- `,
3019
errors: [
2389
- "React Hook useEffect has a missing dependency: 'local'. " +
2390
- 'Either include it or remove the dependency array.',
2391
- 'React Hook useEffect has a complex expression in the dependency array. ' +
2392
- 'Extract it to a separate variable so it can be statically checked.',
3020
+ {
3021
+ message:
3022
+ "React Hook useEffect has a missing dependency: 'local'. " +
3023
+ 'Either include it or remove the dependency array.',
3024
+ // TODO: should we bail out instead?
3025
+ suggestions: [
3026
+ {
3027
+ desc: 'Update the dependencies array to be: [local]',
3028
+ output: normalizeIndent`
3029
+ function MyComponent() {
3030
+ const local = {};
3031
+ useEffect(() => {
3032
+ console.log(local);
3033
+ }, [local]);
3034
+ }
3035
+ `,
3036
+ },
3037
+ ],
3038
+ },
3039
+ {
3040
+ message:
3041
+ 'React Hook useEffect has a complex expression in the dependency array. ' +
3042
+ 'Extract it to a separate variable so it can be statically checked.',
3043
+ suggestions: undefined,
3044
+ },
3045
],
3046
},
3047
{
2396
- code: `
3048
+ code: normalizeIndent`
3049
function MyComponent() {
3050
const ref = useRef();
3051
const [state, setState] = useState();
@@ -2403,25 +3055,33 @@ const tests = {
3055
}, []);
3056
}
3057
`,
2406
- output: `
2407
- function MyComponent() {
2408
- const ref = useRef();
2409
- const [state, setState] = useState();
2410
- useEffect(() => {
2411
- ref.current = {};
2412
- setState(state + 1);
2413
- }, [state]);
2414
- }
2415
- `,
3058
errors: [
2417
- "React Hook useEffect has a missing dependency: 'state'. " +
2418
- 'Either include it or remove the dependency array. ' +
2419
- `You can also do a functional update 'setState(s => ...)' ` +
2420
- `if you only need 'state' in the 'setState' call.`,
3059
+ {
3060
+ message:
3061
+ "React Hook useEffect has a missing dependency: 'state'. " +
3062
+ 'Either include it or remove the dependency array. ' +
3063
+ `You can also do a functional update 'setState(s => ...)' ` +
3064
+ `if you only need 'state' in the 'setState' call.`,
3065
+ suggestions: [
3066
+ {
3067
+ desc: 'Update the dependencies array to be: [state]',
3068
+ output: normalizeIndent`
3069
+ function MyComponent() {
3070
+ const ref = useRef();
3071
+ const [state, setState] = useState();
3072
+ useEffect(() => {
3073
+ ref.current = {};
3074
+ setState(state + 1);
3075
+ }, [state]);
3076
+ }
3077
+ `,
3078
+ },
3079
+ ],
3080
+ },
3081
],
3082
},
3083
{
2424
- code: `
3084
+ code: normalizeIndent`
3085
function MyComponent() {
3086
const ref = useRef();
3087
const [state, setState] = useState();
@@ -2431,28 +3091,36 @@ const tests = {
3091
}, [ref]);
3092
}
3093
`,
2434
- // We don't ask to remove static deps but don't add them either.
2435
- // Don't suggest removing "ref" (it's fine either way)
2436
- // but *do* add "state". *Don't* add "setState" ourselves.
2437
- output: `
2438
- function MyComponent() {
2439
- const ref = useRef();
2440
- const [state, setState] = useState();
2441
- useEffect(() => {
2442
- ref.current = {};
2443
- setState(state + 1);
2444
- }, [ref, state]);
2445
- }
2446
- `,
3094
errors: [
2448
- "React Hook useEffect has a missing dependency: 'state'. " +
2449
- 'Either include it or remove the dependency array. ' +
2450
- `You can also do a functional update 'setState(s => ...)' ` +
2451
- `if you only need 'state' in the 'setState' call.`,
3095
+ {
3096
+ message:
3097
+ "React Hook useEffect has a missing dependency: 'state'. " +
3098
+ 'Either include it or remove the dependency array. ' +
3099
+ `You can also do a functional update 'setState(s => ...)' ` +
3100
+ `if you only need 'state' in the 'setState' call.`,
3101
+ // We don't ask to remove static deps but don't add them either.
3102
+ // Don't suggest removing "ref" (it's fine either way)
3103
+ // but *do* add "state". *Don't* add "setState" ourselves.
3104
+ suggestions: [
3105
+ {
3106
+ desc: 'Update the dependencies array to be: [ref, state]',
3107
+ output: normalizeIndent`
3108
+ function MyComponent() {
3109
+ const ref = useRef();
3110
+ const [state, setState] = useState();
3111
+ useEffect(() => {
3112
+ ref.current = {};
3113
+ setState(state + 1);
3114
+ }, [ref, state]);
3115
+ }
3116
+ `,
3117
+ },
3118
+ ],
3119
+ },
3120
],
3121
},
3122
{
2455
- code: `
3123
+ code: normalizeIndent`
3124
function MyComponent(props) {
3125
const ref1 = useRef();
3126
const ref2 = useRef();
@@ -2464,25 +3132,34 @@ const tests = {
3132
}, []);
3133
}
3134
`,
2467
- output: `
2468
- function MyComponent(props) {
2469
- const ref1 = useRef();
2470
- const ref2 = useRef();
2471
- useEffect(() => {
2472
- ref1.current.focus();
2473
- console.log(ref2.current.textContent);
2474
- alert(props.someOtherRefs.current.innerHTML);
2475
- fetch(props.color);
2476
- }, [props.color, props.someOtherRefs]);
2477
- }
2478
- `,
3135
errors: [
2480
- "React Hook useEffect has missing dependencies: 'props.color' and 'props.someOtherRefs'. " +
2481
- 'Either include them or remove the dependency array.',
3136
+ {
3137
+ message:
3138
+ "React Hook useEffect has missing dependencies: 'props.color' and 'props.someOtherRefs'. " +
3139
+ 'Either include them or remove the dependency array.',
3140
+ suggestions: [
3141
+ {
3142
+ desc:
3143
+ 'Update the dependencies array to be: [props.color, props.someOtherRefs]',
3144
+ output: normalizeIndent`
3145
+ function MyComponent(props) {
3146
+ const ref1 = useRef();
3147
+ const ref2 = useRef();
3148
+ useEffect(() => {
3149
+ ref1.current.focus();
3150
+ console.log(ref2.current.textContent);
3151
+ alert(props.someOtherRefs.current.innerHTML);
3152
+ fetch(props.color);
3153
+ }, [props.color, props.someOtherRefs]);
3154
+ }
3155
+ `,
3156
+ },
3157
+ ],
3158
+ },
3159
],
3160
},
3161
{
2485
- code: `
3162
+ code: normalizeIndent`
3163
function MyComponent(props) {
3164
const ref1 = useRef();
3165
const ref2 = useRef();
@@ -2494,27 +3171,36 @@ const tests = {
3171
}, [ref1.current, ref2.current, props.someOtherRefs, props.color]);
3172
}
3173
`,
2497
- output: `
2498
- function MyComponent(props) {
2499
- const ref1 = useRef();
2500
- const ref2 = useRef();
2501
- useEffect(() => {
2502
- ref1.current.focus();
2503
- console.log(ref2.current.textContent);
2504
- alert(props.someOtherRefs.current.innerHTML);
2505
- fetch(props.color);
2506
- }, [props.someOtherRefs, props.color]);
2507
- }
2508
- `,
3174
errors: [
2510
- "React Hook useEffect has unnecessary dependencies: 'ref1.current' and 'ref2.current'. " +
2511
- 'Either exclude them or remove the dependency array. ' +
2512
- "Mutable values like 'ref1.current' aren't valid dependencies " +
2513
- "because mutating them doesn't re-render the component.",
3175
+ {
3176
+ message:
3177
+ "React Hook useEffect has unnecessary dependencies: 'ref1.current' and 'ref2.current'. " +
3178
+ 'Either exclude them or remove the dependency array. ' +
3179
+ "Mutable values like 'ref1.current' aren't valid dependencies " +
3180
+ "because mutating them doesn't re-render the component.",
3181
+ suggestions: [
3182
+ {
3183
+ desc:
3184
+ 'Update the dependencies array to be: [props.someOtherRefs, props.color]',
3185
+ output: normalizeIndent`
3186
+ function MyComponent(props) {
3187
+ const ref1 = useRef();
3188
+ const ref2 = useRef();
3189
+ useEffect(() => {
3190
+ ref1.current.focus();
3191
+ console.log(ref2.current.textContent);
3192
+ alert(props.someOtherRefs.current.innerHTML);
3193
+ fetch(props.color);
3194
+ }, [props.someOtherRefs, props.color]);
3195
+ }
3196
+ `,
3197
+ },
3198
+ ],
3199
+ },
3200
],
3201
},
3202
{
2517
- code: `
3203
+ code: normalizeIndent`
3204
function MyComponent() {
3205
const ref = useRef();
3206
useEffect(() => {
@@ -2522,23 +3208,31 @@ const tests = {
3208
}, [ref.current]);
3209
}
3210
`,
2525
- output: `
2526
- function MyComponent() {
2527
- const ref = useRef();
2528
- useEffect(() => {
2529
- console.log(ref.current);
2530
- }, []);
2531
- }
2532
- `,
3211
errors: [
2534
- "React Hook useEffect has an unnecessary dependency: 'ref.current'. " +
2535
- 'Either exclude it or remove the dependency array. ' +
2536
- "Mutable values like 'ref.current' aren't valid dependencies " +
2537
- "because mutating them doesn't re-render the component.",
3212
+ {
3213
+ message:
3214
+ "React Hook useEffect has an unnecessary dependency: 'ref.current'. " +
3215
+ 'Either exclude it or remove the dependency array. ' +
3216
+ "Mutable values like 'ref.current' aren't valid dependencies " +
3217
+ "because mutating them doesn't re-render the component.",
3218
+ suggestions: [
3219
+ {
3220
+ desc: 'Update the dependencies array to be: []',
3221
+ output: normalizeIndent`
3222
+ function MyComponent() {
3223
+ const ref = useRef();
3224
+ useEffect(() => {
3225
+ console.log(ref.current);
3226
+ }, []);
3227
+ }
3228
+ `,
3229
+ },
3230
+ ],
3231
+ },
3232
],
3233
},
3234
{
2541
- code: `
3235
+ code: normalizeIndent`
3236
function MyComponent({ activeTab }) {
3237
const ref1 = useRef();
3238
const ref2 = useRef();
@@ -2548,25 +3242,33 @@ const tests = {
3242
}, [ref1.current, ref2.current, activeTab]);
3243
}
3244
`,
2551
- output: `
2552
- function MyComponent({ activeTab }) {
2553
- const ref1 = useRef();
2554
- const ref2 = useRef();
2555
- useEffect(() => {
2556
- ref1.current.scrollTop = 0;
2557
- ref2.current.scrollTop = 0;
2558
- }, [activeTab]);
2559
- }
2560
- `,
3245
errors: [
2562
- "React Hook useEffect has unnecessary dependencies: 'ref1.current' and 'ref2.current'. " +
2563
- 'Either exclude them or remove the dependency array. ' +
2564
- "Mutable values like 'ref1.current' aren't valid dependencies " +
2565
- "because mutating them doesn't re-render the component.",
3246
+ {
3247
+ message:
3248
+ "React Hook useEffect has unnecessary dependencies: 'ref1.current' and 'ref2.current'. " +
3249
+ 'Either exclude them or remove the dependency array. ' +
3250
+ "Mutable values like 'ref1.current' aren't valid dependencies " +
3251
+ "because mutating them doesn't re-render the component.",
3252
+ suggestions: [
3253
+ {
3254
+ desc: 'Update the dependencies array to be: [activeTab]',
3255
+ output: normalizeIndent`
3256
+ function MyComponent({ activeTab }) {
3257
+ const ref1 = useRef();
3258
+ const ref2 = useRef();
3259
+ useEffect(() => {
3260
+ ref1.current.scrollTop = 0;
3261
+ ref2.current.scrollTop = 0;
3262
+ }, [activeTab]);
3263
+ }
3264
+ `,
3265
+ },
3266
+ ],
3267
+ },
3268
],
3269
},
3270
{
2569
- code: `
3271
+ code: normalizeIndent`
3272
function MyComponent({ activeTab, initY }) {
3273
const ref1 = useRef();
3274
const ref2 = useRef();
@@ -2576,25 +3278,33 @@ const tests = {
3278
}, [ref1.current, ref2.current, activeTab, initY]);
3279
}
3280
`,
2579
- output: `
2580
- function MyComponent({ activeTab, initY }) {
2581
- const ref1 = useRef();
2582
- const ref2 = useRef();
2583
- const fn = useCallback(() => {
2584
- ref1.current.scrollTop = initY;
2585
- ref2.current.scrollTop = initY;
2586
- }, [initY]);
2587
- }
2588
- `,
3281
errors: [
2590
- "React Hook useCallback has unnecessary dependencies: 'activeTab', 'ref1.current', and 'ref2.current'. " +
2591
- 'Either exclude them or remove the dependency array. ' +
2592
- "Mutable values like 'ref1.current' aren't valid dependencies " +
2593
- "because mutating them doesn't re-render the component.",
3282
+ {
3283
+ message:
3284
+ "React Hook useCallback has unnecessary dependencies: 'activeTab', 'ref1.current', and 'ref2.current'. " +
3285
+ 'Either exclude them or remove the dependency array. ' +
3286
+ "Mutable values like 'ref1.current' aren't valid dependencies " +
3287
+ "because mutating them doesn't re-render the component.",
3288
+ suggestions: [
3289
+ {
3290
+ desc: 'Update the dependencies array to be: [initY]',
3291
+ output: normalizeIndent`
3292
+ function MyComponent({ activeTab, initY }) {
3293
+ const ref1 = useRef();
3294
+ const ref2 = useRef();
3295
+ const fn = useCallback(() => {
3296
+ ref1.current.scrollTop = initY;
3297
+ ref2.current.scrollTop = initY;
3298
+ }, [initY]);
3299
+ }
3300
+ `,
3301
+ },
3302
+ ],
3303
+ },
3304
],
3305
},
3306
{
2597
- code: `
3307
+ code: normalizeIndent`
3308
function MyComponent() {
3309
const ref = useRef();
3310
useEffect(() => {
@@ -2602,23 +3312,31 @@ const tests = {
3312
}, [ref.current, ref]);
3313
}
3314
`,
2605
- output: `
2606
- function MyComponent() {
2607
- const ref = useRef();
2608
- useEffect(() => {
2609
- console.log(ref.current);
2610
- }, [ref]);
2611
- }
2612
- `,
3315
errors: [
2614
- "React Hook useEffect has an unnecessary dependency: 'ref.current'. " +
2615
- 'Either exclude it or remove the dependency array. ' +
2616
- "Mutable values like 'ref.current' aren't valid dependencies " +
2617
- "because mutating them doesn't re-render the component.",
3316
+ {
3317
+ message:
3318
+ "React Hook useEffect has an unnecessary dependency: 'ref.current'. " +
3319
+ 'Either exclude it or remove the dependency array. ' +
3320
+ "Mutable values like 'ref.current' aren't valid dependencies " +
3321
+ "because mutating them doesn't re-render the component.",
3322
+ suggestions: [
3323
+ {
3324
+ desc: 'Update the dependencies array to be: [ref]',
3325
+ output: normalizeIndent`
3326
+ function MyComponent() {
3327
+ const ref = useRef();
3328
+ useEffect(() => {
3329
+ console.log(ref.current);
3330
+ }, [ref]);
3331
+ }
3332
+ `,
3333
+ },
3334
+ ],
3335
+ },
3336
],
3337
},
3338
{
2621
- code: `
3339
+ code: normalizeIndent`
3340
const MyComponent = forwardRef((props, ref) => {
3341
useImperativeHandle(ref, () => ({
3342
focus() {
@@ -2627,22 +3345,30 @@ const tests = {
3345
}), [])
3346
});
3347
`,
2630
- output: `
2631
- const MyComponent = forwardRef((props, ref) => {
2632
- useImperativeHandle(ref, () => ({
2633
- focus() {
2634
- alert(props.hello);
2635
- }
2636
- }), [props.hello])
2637
- });
2638
- `,
3348
errors: [
2640
- "React Hook useImperativeHandle has a missing dependency: 'props.hello'. " +
2641
- 'Either include it or remove the dependency array.',
3349
+ {
3350
+ message:
3351
+ "React Hook useImperativeHandle has a missing dependency: 'props.hello'. " +
3352
+ 'Either include it or remove the dependency array.',
3353
+ suggestions: [
3354
+ {
3355
+ desc: 'Update the dependencies array to be: [props.hello]',
3356
+ output: normalizeIndent`
3357
+ const MyComponent = forwardRef((props, ref) => {
3358
+ useImperativeHandle(ref, () => ({
3359
+ focus() {
3360
+ alert(props.hello);
3361
+ }
3362
+ }), [props.hello])
3363
+ });
3364
+ `,
3365
+ },
3366
+ ],
3367
+ },
3368
],
3369
},
3370
{
2645
- code: `
3371
+ code: normalizeIndent`
3372
function MyComponent(props) {
3373
useEffect(() => {
3374
if (props.onChange) {
@@ -2651,29 +3377,37 @@ const tests = {
3377
}, []);
3378
}
3379
`,
2654
- output: `
2655
- function MyComponent(props) {
2656
- useEffect(() => {
2657
- if (props.onChange) {
2658
- props.onChange();
2659
- }
2660
- }, [props]);
2661
- }
2662
- `,
3380
errors: [
2664
- "React Hook useEffect has a missing dependency: 'props'. " +
2665
- 'Either include it or remove the dependency array. ' +
2666
- `However, 'props' will change when *any* prop changes, so the ` +
2667
- `preferred fix is to destructure the 'props' object outside ` +
2668
- `of the useEffect call and refer to those specific ` +
2669
- `props inside useEffect.`,
3381
+ {
3382
+ message:
3383
+ "React Hook useEffect has a missing dependency: 'props'. " +
3384
+ 'Either include it or remove the dependency array. ' +
3385
+ `However, 'props' will change when *any* prop changes, so the ` +
3386
+ `preferred fix is to destructure the 'props' object outside ` +
3387
+ `of the useEffect call and refer to those specific ` +
3388
+ `props inside useEffect.`,
3389
+ suggestions: [
3390
+ {
3391
+ desc: 'Update the dependencies array to be: [props]',
3392
+ output: normalizeIndent`
3393
+ function MyComponent(props) {
3394
+ useEffect(() => {
3395
+ if (props.onChange) {
3396
+ props.onChange();
3397
+ }
3398
+ }, [props]);
3399
+ }
3400
+ `,
3401
+ },
3402
+ ],
3403
+ },
3404
],
3405
},
3406
{
2673
- code: `
3407
+ code: normalizeIndent`
3408
function MyComponent(props) {
3409
useEffect(() => {
2676
- function play() {
3410
+ function play() {
3411
props.onPlay();
3412
}
3413
function pause() {
@@ -2682,29 +3416,37 @@ const tests = {
3416
}, []);
3417
}
3418
`,
2685
- output: `
2686
- function MyComponent(props) {
2687
- useEffect(() => {
2688
- function play() {
2689
- props.onPlay();
2690
- }
2691
- function pause() {
2692
- props.onPause();
2693
- }
2694
- }, [props]);
2695
- }
2696
- `,
3419
errors: [
2698
- "React Hook useEffect has a missing dependency: 'props'. " +
2699
- 'Either include it or remove the dependency array. ' +
2700
- `However, 'props' will change when *any* prop changes, so the ` +
2701
- `preferred fix is to destructure the 'props' object outside ` +
2702
- `of the useEffect call and refer to those specific ` +
2703
- `props inside useEffect.`,
3420
+ {
3421
+ message:
3422
+ "React Hook useEffect has a missing dependency: 'props'. " +
3423
+ 'Either include it or remove the dependency array. ' +
3424
+ `However, 'props' will change when *any* prop changes, so the ` +
3425
+ `preferred fix is to destructure the 'props' object outside ` +
3426
+ `of the useEffect call and refer to those specific ` +
3427
+ `props inside useEffect.`,
3428
+ suggestions: [
3429
+ {
3430
+ desc: 'Update the dependencies array to be: [props]',
3431
+ output: normalizeIndent`
3432
+ function MyComponent(props) {
3433
+ useEffect(() => {
3434
+ function play() {
3435
+ props.onPlay();
3436
+ }
3437
+ function pause() {
3438
+ props.onPause();
3439
+ }
3440
+ }, [props]);
3441
+ }
3442
+ `,
3443
+ },
3444
+ ],
3445
+ },
3446
],
3447
},
3448
{
2707
- code: `
3449
+ code: normalizeIndent`
3450
function MyComponent(props) {
3451
useEffect(() => {
3452
if (props.foo.onChange) {
@@ -2713,22 +3455,30 @@ const tests = {
3455
}, []);
3456
}
3457
`,
2716
- output: `
2717
- function MyComponent(props) {
2718
- useEffect(() => {
2719
- if (props.foo.onChange) {
2720
- props.foo.onChange();
2721
- }
2722
- }, [props.foo]);
2723
- }
2724
- `,
3458
errors: [
2726
- "React Hook useEffect has a missing dependency: 'props.foo'. " +
2727
- 'Either include it or remove the dependency array.',
3459
+ {
3460
+ message:
3461
+ "React Hook useEffect has a missing dependency: 'props.foo'. " +
3462
+ 'Either include it or remove the dependency array.',
3463
+ suggestions: [
3464
+ {
3465
+ desc: 'Update the dependencies array to be: [props.foo]',
3466
+ output: normalizeIndent`
3467
+ function MyComponent(props) {
3468
+ useEffect(() => {
3469
+ if (props.foo.onChange) {
3470
+ props.foo.onChange();
3471
+ }
3472
+ }, [props.foo]);
3473
+ }
3474
+ `,
3475
+ },
3476
+ ],
3477
+ },
3478
],
3479
},
3480
{
2731
- code: `
3481
+ code: normalizeIndent`
3482
function MyComponent(props) {
3483
useEffect(() => {
3484
props.onChange();
@@ -2738,27 +3488,35 @@ const tests = {
3488
}, []);
3489
}
3490
`,
2741
- output: `
2742
- function MyComponent(props) {
2743
- useEffect(() => {
2744
- props.onChange();
2745
- if (props.foo.onChange) {
2746
- props.foo.onChange();
2747
- }
2748
- }, [props]);
2749
- }
2750
- `,
3491
errors: [
2752
- "React Hook useEffect has a missing dependency: 'props'. " +
2753
- 'Either include it or remove the dependency array. ' +
2754
- `However, 'props' will change when *any* prop changes, so the ` +
2755
- `preferred fix is to destructure the 'props' object outside ` +
2756
- `of the useEffect call and refer to those specific ` +
2757
- `props inside useEffect.`,
3492
+ {
3493
+ message:
3494
+ "React Hook useEffect has a missing dependency: 'props'. " +
3495
+ 'Either include it or remove the dependency array. ' +
3496
+ `However, 'props' will change when *any* prop changes, so the ` +
3497
+ `preferred fix is to destructure the 'props' object outside ` +
3498
+ `of the useEffect call and refer to those specific ` +
3499
+ `props inside useEffect.`,
3500
+ suggestions: [
3501
+ {
3502
+ desc: 'Update the dependencies array to be: [props]',
3503
+ output: normalizeIndent`
3504
+ function MyComponent(props) {
3505
+ useEffect(() => {
3506
+ props.onChange();
3507
+ if (props.foo.onChange) {
3508
+ props.foo.onChange();
3509
+ }
3510
+ }, [props]);
3511
+ }
3512
+ `,
3513
+ },
3514
+ ],
3515
+ },
3516
],
3517
},
3518
{
2761
- code: `
3519
+ code: normalizeIndent`
3520
function MyComponent(props) {
3521
const [skillsCount] = useState();
3522
useEffect(() => {
@@ -2768,27 +3526,36 @@ const tests = {
3526
}, [skillsCount, props.isEditMode, props.toggleEditMode]);
3527
}
3528
`,
2771
- output: `
2772
- function MyComponent(props) {
2773
- const [skillsCount] = useState();
2774
- useEffect(() => {
2775
- if (skillsCount === 0 && !props.isEditMode) {
2776
- props.toggleEditMode();
2777
- }
2778
- }, [skillsCount, props.isEditMode, props.toggleEditMode, props]);
2779
- }
2780
- `,
3529
errors: [
2782
- "React Hook useEffect has a missing dependency: 'props'. " +
2783
- 'Either include it or remove the dependency array. ' +
2784
- `However, 'props' will change when *any* prop changes, so the ` +
2785
- `preferred fix is to destructure the 'props' object outside ` +
2786
- `of the useEffect call and refer to those specific ` +
2787
- `props inside useEffect.`,
3530
+ {
3531
+ message:
3532
+ "React Hook useEffect has a missing dependency: 'props'. " +
3533
+ 'Either include it or remove the dependency array. ' +
3534
+ `However, 'props' will change when *any* prop changes, so the ` +
3535
+ `preferred fix is to destructure the 'props' object outside ` +
3536
+ `of the useEffect call and refer to those specific ` +
3537
+ `props inside useEffect.`,
3538
+ suggestions: [
3539
+ {
3540
+ desc:
3541
+ 'Update the dependencies array to be: [skillsCount, props.isEditMode, props.toggleEditMode, props]',
3542
+ output: normalizeIndent`
3543
+ function MyComponent(props) {
3544
+ const [skillsCount] = useState();
3545
+ useEffect(() => {
3546
+ if (skillsCount === 0 && !props.isEditMode) {
3547
+ props.toggleEditMode();
3548
+ }
3549
+ }, [skillsCount, props.isEditMode, props.toggleEditMode, props]);
3550
+ }
3551
+ `,
3552
+ },
3553
+ ],
3554
+ },
3555
],
3556
},
3557
{
2791
- code: `
3558
+ code: normalizeIndent`
3559
function MyComponent(props) {
3560
const [skillsCount] = useState();
3561
useEffect(() => {
@@ -2798,27 +3565,35 @@ const tests = {
3565
}, []);
3566
}
3567
`,
2801
- output: `
2802
- function MyComponent(props) {
2803
- const [skillsCount] = useState();
2804
- useEffect(() => {
2805
- if (skillsCount === 0 && !props.isEditMode) {
2806
- props.toggleEditMode();
2807
- }
2808
- }, [props, skillsCount]);
2809
- }
2810
- `,
3568
errors: [
2812
- "React Hook useEffect has missing dependencies: 'props' and 'skillsCount'. " +
2813
- 'Either include them or remove the dependency array. ' +
2814
- `However, 'props' will change when *any* prop changes, so the ` +
2815
- `preferred fix is to destructure the 'props' object outside ` +
2816
- `of the useEffect call and refer to those specific ` +
2817
- `props inside useEffect.`,
3569
+ {
3570
+ message:
3571
+ "React Hook useEffect has missing dependencies: 'props' and 'skillsCount'. " +
3572
+ 'Either include them or remove the dependency array. ' +
3573
+ `However, 'props' will change when *any* prop changes, so the ` +
3574
+ `preferred fix is to destructure the 'props' object outside ` +
3575
+ `of the useEffect call and refer to those specific ` +
3576
+ `props inside useEffect.`,
3577
+ suggestions: [
3578
+ {
3579
+ desc: 'Update the dependencies array to be: [props, skillsCount]',
3580
+ output: normalizeIndent`
3581
+ function MyComponent(props) {
3582
+ const [skillsCount] = useState();
3583
+ useEffect(() => {
3584
+ if (skillsCount === 0 && !props.isEditMode) {
3585
+ props.toggleEditMode();
3586
+ }
3587
+ }, [props, skillsCount]);
3588
+ }
3589
+ `,
3590
+ },
3591
+ ],
3592
+ },
3593
],
3594
},
3595
{
2821
- code: `
3596
+ code: normalizeIndent`
3597
function MyComponent(props) {
3598
useEffect(() => {
3599
externalCall(props);
@@ -2826,22 +3601,30 @@ const tests = {
3601
}, []);
3602
}
3603
`,
2829
- output: `
2830
- function MyComponent(props) {
2831
- useEffect(() => {
2832
- externalCall(props);
2833
- props.onChange();
2834
- }, [props]);
2835
- }
2836
- `,
3604
// Don't suggest to destructure props here since you can't.
3605
errors: [
2839
- "React Hook useEffect has a missing dependency: 'props'. " +
2840
- 'Either include it or remove the dependency array.',
3606
+ {
3607
+ message:
3608
+ "React Hook useEffect has a missing dependency: 'props'. " +
3609
+ 'Either include it or remove the dependency array.',
3610
+ suggestions: [
3611
+ {
3612
+ desc: 'Update the dependencies array to be: [props]',
3613
+ output: normalizeIndent`
3614
+ function MyComponent(props) {
3615
+ useEffect(() => {
3616
+ externalCall(props);
3617
+ props.onChange();
3618
+ }, [props]);
3619
+ }
3620
+ `,
3621
+ },
3622
+ ],
3623
+ },
3624
],
3625
},
3626
{
2844
- code: `
3627
+ code: normalizeIndent`
3628
function MyComponent(props) {
3629
useEffect(() => {
3630
props.onChange();
@@ -2849,22 +3632,30 @@ const tests = {
3632
}, []);
3633
}
3634
`,
2852
- output: `
2853
- function MyComponent(props) {
2854
- useEffect(() => {
2855
- props.onChange();
2856
- externalCall(props);
2857
- }, [props]);
2858
- }
2859
- `,
3635
// Don't suggest to destructure props here since you can't.
3636
errors: [
2862
- "React Hook useEffect has a missing dependency: 'props'. " +
2863
- 'Either include it or remove the dependency array.',
3637
+ {
3638
+ message:
3639
+ "React Hook useEffect has a missing dependency: 'props'. " +
3640
+ 'Either include it or remove the dependency array.',
3641
+ suggestions: [
3642
+ {
3643
+ desc: 'Update the dependencies array to be: [props]',
3644
+ output: normalizeIndent`
3645
+ function MyComponent(props) {
3646
+ useEffect(() => {
3647
+ props.onChange();
3648
+ externalCall(props);
3649
+ }, [props]);
3650
+ }
3651
+ `,
3652
+ },
3653
+ ],
3654
+ },
3655
],
3656
},
3657
{
2867
- code: `
3658
+ code: normalizeIndent`
3659
function MyComponent(props) {
3660
let value;
3661
let value2;
@@ -2888,54 +3679,48 @@ const tests = {
3679
`,
3680
// This is a separate warning unrelated to others.
3681
// We could've made a separate rule for it but it's rare enough to name it.
2891
- // No autofix suggestion because the intent isn't clear.
2892
- output: `
2893
- function MyComponent(props) {
2894
- let value;
2895
- let value2;
2896
- let value3;
2897
- let value4;
2898
- let asyncValue;
2899
- useEffect(() => {
2900
- if (value4) {
2901
- value = {};
2902
- }
2903
- value2 = 100;
2904
- value = 43;
2905
- value4 = true;
2906
- console.log(value2);
2907
- console.log(value3);
2908
- setTimeout(() => {
2909
- asyncValue = 100;
2910
- });
2911
- }, []);
2912
- }
2913
- `,
3682
+ // No suggestions because the intent isn't clear.
3683
errors: [
2915
- // value2
2916
- `Assignments to the 'value2' variable from inside React Hook useEffect ` +
2917
- `will be lost after each render. To preserve the value over time, ` +
2918
- `store it in a useRef Hook and keep the mutable value in the '.current' property. ` +
2919
- `Otherwise, you can move this variable directly inside useEffect.`,
2920
- // value
2921
- `Assignments to the 'value' variable from inside React Hook useEffect ` +
2922
- `will be lost after each render. To preserve the value over time, ` +
2923
- `store it in a useRef Hook and keep the mutable value in the '.current' property. ` +
2924
- `Otherwise, you can move this variable directly inside useEffect.`,
2925
- // value4
2926
- `Assignments to the 'value4' variable from inside React Hook useEffect ` +
2927
- `will be lost after each render. To preserve the value over time, ` +
2928
- `store it in a useRef Hook and keep the mutable value in the '.current' property. ` +
2929
- `Otherwise, you can move this variable directly inside useEffect.`,
2930
- // asyncValue
2931
- `Assignments to the 'asyncValue' variable from inside React Hook useEffect ` +
2932
- `will be lost after each render. To preserve the value over time, ` +
2933
- `store it in a useRef Hook and keep the mutable value in the '.current' property. ` +
2934
- `Otherwise, you can move this variable directly inside useEffect.`,
3684
+ {
3685
+ message:
3686
+ // value2
3687
+ `Assignments to the 'value2' variable from inside React Hook useEffect ` +
3688
+ `will be lost after each render. To preserve the value over time, ` +
3689
+ `store it in a useRef Hook and keep the mutable value in the '.current' property. ` +
3690
+ `Otherwise, you can move this variable directly inside useEffect.`,
3691
+ suggestions: undefined,
3692
+ },
3693
+ {
3694
+ message:
3695
+ // value
3696
+ `Assignments to the 'value' variable from inside React Hook useEffect ` +
3697
+ `will be lost after each render. To preserve the value over time, ` +
3698
+ `store it in a useRef Hook and keep the mutable value in the '.current' property. ` +
3699
+ `Otherwise, you can move this variable directly inside useEffect.`,
3700
+ suggestions: undefined,
3701
+ },
3702
+ {
3703
+ message:
3704
+ // value4
3705
+ `Assignments to the 'value4' variable from inside React Hook useEffect ` +
3706
+ `will be lost after each render. To preserve the value over time, ` +
3707
+ `store it in a useRef Hook and keep the mutable value in the '.current' property. ` +
3708
+ `Otherwise, you can move this variable directly inside useEffect.`,
3709
+ suggestions: undefined,
3710
+ },
3711
+ {
3712
+ message:
3713
+ // asyncValue
3714
+ `Assignments to the 'asyncValue' variable from inside React Hook useEffect ` +
3715
+ `will be lost after each render. To preserve the value over time, ` +
3716
+ `store it in a useRef Hook and keep the mutable value in the '.current' property. ` +
3717
+ `Otherwise, you can move this variable directly inside useEffect.`,
3718
+ suggestions: undefined,
3719
+ },
3720
],
3721
},
3722
{
2938
- code: `
3723
+ code: normalizeIndent`
3724
function MyComponent(props) {
3725
let value;
3726
let value2;
@@ -2955,56 +3740,39 @@ const tests = {
3740
`,
3741
// This is a separate warning unrelated to others.
3742
// We could've made a separate rule for it but it's rare enough to name it.
2958
- // No autofix suggestion because the intent isn't clear.
2959
- output: `
2960
- function MyComponent(props) {
2961
- let value;
2962
- let value2;
2963
- let value3;
2964
- let asyncValue;
2965
- useEffect(() => {
2966
- value = {};
2967
- value2 = 100;
2968
- value = 43;
2969
- console.log(value2);
2970
- console.log(value3);
2971
- setTimeout(() => {
2972
- asyncValue = 100;
2973
- });
2974
- }, [value, value2, value3]);
2975
- }
2976
- `,
3743
+ // No suggestions because the intent isn't clear.
3744
errors: [
2978
- // value
2979
- `Assignments to the 'value' variable from inside React Hook useEffect ` +
2980
- `will be lost after each render. To preserve the value over time, ` +
2981
- `store it in a useRef Hook and keep the mutable value in the '.current' property. ` +
2982
- `Otherwise, you can move this variable directly inside useEffect.`,
2983
- // value2
2984
- `Assignments to the 'value2' variable from inside React Hook useEffect ` +
2985
- `will be lost after each render. To preserve the value over time, ` +
2986
- `store it in a useRef Hook and keep the mutable value in the '.current' property. ` +
2987
- `Otherwise, you can move this variable directly inside useEffect.`,
2988
- // asyncValue
2989
- `Assignments to the 'asyncValue' variable from inside React Hook useEffect ` +
2990
- `will be lost after each render. To preserve the value over time, ` +
2991
- `store it in a useRef Hook and keep the mutable value in the '.current' property. ` +
2992
- `Otherwise, you can move this variable directly inside useEffect.`,
3745
+ {
3746
+ message:
3747
+ // value
3748
+ `Assignments to the 'value' variable from inside React Hook useEffect ` +
3749
+ `will be lost after each render. To preserve the value over time, ` +
3750
+ `store it in a useRef Hook and keep the mutable value in the '.current' property. ` +
3751
+ `Otherwise, you can move this variable directly inside useEffect.`,
3752
+ suggestions: undefined,
3753
+ },
3754
+ {
3755
+ message:
3756
+ // value2
3757
+ `Assignments to the 'value2' variable from inside React Hook useEffect ` +
3758
+ `will be lost after each render. To preserve the value over time, ` +
3759
+ `store it in a useRef Hook and keep the mutable value in the '.current' property. ` +
3760
+ `Otherwise, you can move this variable directly inside useEffect.`,
3761
+ suggestions: undefined,
3762
+ },
3763
+ {
3764
+ message:
3765
+ // asyncValue
3766
+ `Assignments to the 'asyncValue' variable from inside React Hook useEffect ` +
3767
+ `will be lost after each render. To preserve the value over time, ` +
3768
+ `store it in a useRef Hook and keep the mutable value in the '.current' property. ` +
3769
+ `Otherwise, you can move this variable directly inside useEffect.`,
3770
+ suggestions: undefined,
3771
+ },
3772
],
3773
},
3774
{
2996
- code: `
2997
- function MyComponent() {
2998
- const myRef = useRef();
2999
- useEffect(() => {
3000
- const handleMove = () => {};
3001
- myRef.current.addEventListener('mousemove', handleMove);
3002
- return () => myRef.current.removeEventListener('mousemove', handleMove);
3003
- }, []);
3004
- return <div ref={myRef} />;
3005
- }
3006
- `,
3007
- output: `
3775
+ code: normalizeIndent`
3776
function MyComponent() {
3777
const myRef = useRef();
3778
useEffect(() => {
@@ -3016,25 +3784,18 @@ const tests = {
3784
}
3785
`,
3786
errors: [
3019
- `The ref value 'myRef.current' will likely have changed by the time ` +
3020
- `this effect cleanup function runs. If this ref points to a node ` +
3021
- `rendered by React, copy 'myRef.current' to a variable inside the effect, ` +
3022
- `and use that variable in the cleanup function.`,
3787
+ {
3788
+ message:
3789
+ `The ref value 'myRef.current' will likely have changed by the time ` +
3790
+ `this effect cleanup function runs. If this ref points to a node ` +
3791
+ `rendered by React, copy 'myRef.current' to a variable inside the effect, ` +
3792
+ `and use that variable in the cleanup function.`,
3793
+ suggestions: undefined,
3794
+ },
3795
],
3796
},
3797
{
3026
- code: `
3027
- function MyComponent() {
3028
- const myRef = useRef();
3029
- useEffect(() => {
3030
- const handleMove = () => {};
3031
- myRef.current.addEventListener('mousemove', handleMove);
3032
- return () => myRef.current.removeEventListener('mousemove', handleMove);
3033
- });
3034
- return <div ref={myRef} />;
3035
- }
3036
- `,
3037
- output: `
3798
+ code: normalizeIndent`
3799
function MyComponent() {
3800
const myRef = useRef();
3801
useEffect(() => {
@@ -3046,23 +3807,18 @@ const tests = {
3807
}
3808
`,
3809
errors: [
3049
- `The ref value 'myRef.current' will likely have changed by the time ` +
3050
- `this effect cleanup function runs. If this ref points to a node ` +
3051
- `rendered by React, copy 'myRef.current' to a variable inside the effect, ` +
3052
- `and use that variable in the cleanup function.`,
3810
+ {
3811
+ message:
3812
+ `The ref value 'myRef.current' will likely have changed by the time ` +
3813
+ `this effect cleanup function runs. If this ref points to a node ` +
3814
+ `rendered by React, copy 'myRef.current' to a variable inside the effect, ` +
3815
+ `and use that variable in the cleanup function.`,
3816
+ suggestions: undefined,
3817
+ },
3818
],
3819
},
3820
{
3056
- code: `
3057
- function useMyThing(myRef) {
3058
- useEffect(() => {
3059
- const handleMove = () => {};
3060
- myRef.current.addEventListener('mousemove', handleMove);
3061
- return () => myRef.current.removeEventListener('mousemove', handleMove);
3062
- }, [myRef]);
3063
- }
3064
- `,
3065
- output: `
3821
+ code: normalizeIndent`
3822
function useMyThing(myRef) {
3823
useEffect(() => {
3824
const handleMove = () => {};
@@ -3072,29 +3828,18 @@ const tests = {
3828
}
3829
`,
3830
errors: [
3075
- `The ref value 'myRef.current' will likely have changed by the time ` +
3076
- `this effect cleanup function runs. If this ref points to a node ` +
3077
- `rendered by React, copy 'myRef.current' to a variable inside the effect, ` +
3078
- `and use that variable in the cleanup function.`,
3831
+ {
3832
+ message:
3833
+ `The ref value 'myRef.current' will likely have changed by the time ` +
3834
+ `this effect cleanup function runs. If this ref points to a node ` +
3835
+ `rendered by React, copy 'myRef.current' to a variable inside the effect, ` +
3836
+ `and use that variable in the cleanup function.`,
3837
+ suggestions: undefined,
3838
+ },
3839
],
3840
},
3841
{
3082
- code: `
3083
- function useMyThing(myRef) {
3084
- useEffect(() => {
3085
- const handleMouse = () => {};
3086
- myRef.current.addEventListener('mousemove', handleMouse);
3087
- myRef.current.addEventListener('mousein', handleMouse);
3088
- return function() {
3089
- setTimeout(() => {
3090
- myRef.current.removeEventListener('mousemove', handleMouse);
3091
- myRef.current.removeEventListener('mousein', handleMouse);
3092
- });
3093
- }
3094
- }, [myRef]);
3095
- }
3096
- `,
3097
- output: `
3842
+ code: normalizeIndent`
3843
function useMyThing(myRef) {
3844
useEffect(() => {
3845
const handleMouse = () => {};
@@ -3110,29 +3855,18 @@ const tests = {
3855
}
3856
`,
3857
errors: [
3113
- `The ref value 'myRef.current' will likely have changed by the time ` +
3114
- `this effect cleanup function runs. If this ref points to a node ` +
3115
- `rendered by React, copy 'myRef.current' to a variable inside the effect, ` +
3116
- `and use that variable in the cleanup function.`,
3858
+ {
3859
+ message:
3860
+ `The ref value 'myRef.current' will likely have changed by the time ` +
3861
+ `this effect cleanup function runs. If this ref points to a node ` +
3862
+ `rendered by React, copy 'myRef.current' to a variable inside the effect, ` +
3863
+ `and use that variable in the cleanup function.`,
3864
+ suggestions: undefined,
3865
+ },
3866
],
3867
},
3868
{
3120
- code: `
3121
- function useMyThing(myRef, active) {
3122
- useEffect(() => {
3123
- const handleMove = () => {};
3124
- if (active) {
3125
- myRef.current.addEventListener('mousemove', handleMove);
3126
- return function() {
3127
- setTimeout(() => {
3128
- myRef.current.removeEventListener('mousemove', handleMove);
3129
- });
3130
- }
3131
- }
3132
- }, [myRef, active]);
3133
- }
3134
- `,
3135
- output: `
3869
+ code: normalizeIndent`
3870
function useMyThing(myRef, active) {
3871
useEffect(() => {
3872
const handleMove = () => {};
@@ -3148,10 +3882,14 @@ const tests = {
3882
}
3883
`,
3884
errors: [
3151
- `The ref value 'myRef.current' will likely have changed by the time ` +
3152
- `this effect cleanup function runs. If this ref points to a node ` +
3153
- `rendered by React, copy 'myRef.current' to a variable inside the effect, ` +
3154
- `and use that variable in the cleanup function.`,
3885
+ {
3886
+ message:
3887
+ `The ref value 'myRef.current' will likely have changed by the time ` +
3888
+ `this effect cleanup function runs. If this ref points to a node ` +
3889
+ `rendered by React, copy 'myRef.current' to a variable inside the effect, ` +
3890
+ `and use that variable in the cleanup function.`,
3891
+ suggestions: undefined,
3892
+ },
3893
],
3894
},
3895
{
@@ -3187,41 +3925,50 @@ const tests = {
3925
},
3926
{
3927
// Autofix ignores constant primitives (leaving the ones that are there).
3190
- code: `
3191
- function MyComponent() {
3192
- const local1 = 42;
3193
- const local2 = '42';
3194
- const local3 = null;
3195
- const local4 = {};
3196
- useEffect(() => {
3197
- console.log(local1);
3198
- console.log(local2);
3199
- console.log(local3);
3200
- console.log(local4);
3201
- }, [local1, local3]);
3202
- }
3203
- `,
3204
- output: `
3205
- function MyComponent() {
3206
- const local1 = 42;
3207
- const local2 = '42';
3208
- const local3 = null;
3209
- const local4 = {};
3210
- useEffect(() => {
3211
- console.log(local1);
3212
- console.log(local2);
3213
- console.log(local3);
3214
- console.log(local4);
3215
- }, [local1, local3, local4]);
3216
- }
3217
- `,
3928
+ code: normalizeIndent`
3929
+ function MyComponent() {
3930
+ const local1 = 42;
3931
+ const local2 = '42';
3932
+ const local3 = null;
3933
+ const local4 = {};
3934
+ useEffect(() => {
3935
+ console.log(local1);
3936
+ console.log(local2);
3937
+ console.log(local3);
3938
+ console.log(local4);
3939
+ }, [local1, local3]);
3940
+ }
3941
+ `,
3942
errors: [
3219
- "React Hook useEffect has a missing dependency: 'local4'. " +
3220
- 'Either include it or remove the dependency array.',
3943
+ {
3944
+ message:
3945
+ "React Hook useEffect has a missing dependency: 'local4'. " +
3946
+ 'Either include it or remove the dependency array.',
3947
+ suggestions: [
3948
+ {
3949
+ desc:
3950
+ 'Update the dependencies array to be: [local1, local3, local4]',
3951
+ output: normalizeIndent`
3952
+ function MyComponent() {
3953
+ const local1 = 42;
3954
+ const local2 = '42';
3955
+ const local3 = null;
3956
+ const local4 = {};
3957
+ useEffect(() => {
3958
+ console.log(local1);
3959
+ console.log(local2);
3960
+ console.log(local3);
3961
+ console.log(local4);
3962
+ }, [local1, local3, local4]);
3963
+ }
3964
+ `,
3965
+ },
3966
+ ],
3967
+ },
3968
],
3969
},
3970
{
3224
- code: `
3971
+ code: normalizeIndent`
3972
function MyComponent() {
3973
useEffect(() => {
3974
window.scrollTo(0, 0);
@@ -3229,14 +3976,29 @@ const tests = {
3976
}
3977
`,
3978
errors: [
3232
- "React Hook useEffect has an unnecessary dependency: 'window'. " +
3233
- 'Either exclude it or remove the dependency array. ' +
3234
- "Outer scope values like 'window' aren't valid dependencies " +
3235
- "because mutating them doesn't re-render the component.",
3979
+ {
3980
+ message:
3981
+ "React Hook useEffect has an unnecessary dependency: 'window'. " +
3982
+ 'Either exclude it or remove the dependency array. ' +
3983
+ "Outer scope values like 'window' aren't valid dependencies " +
3984
+ "because mutating them doesn't re-render the component.",
3985
+ suggestions: [
3986
+ {
3987
+ desc: 'Update the dependencies array to be: []',
3988
+ output: normalizeIndent`
3989
+ function MyComponent() {
3990
+ useEffect(() => {
3991
+ window.scrollTo(0, 0);
3992
+ }, []);
3993
+ }
3994
+ `,
3995
+ },
3996
+ ],
3997
+ },
3998
],
3999
},
4000
{
3239
- code: `
4001
+ code: normalizeIndent`
4002
import MutableStore from 'store';
4003
4004
function MyComponent() {
@@ -3245,24 +4007,32 @@ const tests = {
4007
}, [MutableStore.hello]);
4008
}
4009
`,
3248
- output: `
3249
- import MutableStore from 'store';
3250
-
3251
- function MyComponent() {
3252
- useEffect(() => {
3253
- console.log(MutableStore.hello);
3254
- }, []);
3255
- }
3256
- `,
4010
errors: [
3258
- "React Hook useEffect has an unnecessary dependency: 'MutableStore.hello'. " +
3259
- 'Either exclude it or remove the dependency array. ' +
3260
- "Outer scope values like 'MutableStore.hello' aren't valid dependencies " +
3261
- "because mutating them doesn't re-render the component.",
4011
+ {
4012
+ message:
4013
+ "React Hook useEffect has an unnecessary dependency: 'MutableStore.hello'. " +
4014
+ 'Either exclude it or remove the dependency array. ' +
4015
+ "Outer scope values like 'MutableStore.hello' aren't valid dependencies " +
4016
+ "because mutating them doesn't re-render the component.",
4017
+ suggestions: [
4018
+ {
4019
+ desc: 'Update the dependencies array to be: []',
4020
+ output: normalizeIndent`
4021
+ import MutableStore from 'store';
4022
+
4023
+ function MyComponent() {
4024
+ useEffect(() => {
4025
+ console.log(MutableStore.hello);
4026
+ }, []);
4027
+ }
4028
+ `,
4029
+ },
4030
+ ],
4031
+ },
4032
],
4033
},
4034
{
3265
- code: `
4035
+ code: normalizeIndent`
4036
import MutableStore from 'store';
4037
let z = {};
4038
@@ -3276,30 +4046,38 @@ const tests = {
4046
}
4047
}
4048
`,
3279
- output: `
3280
- import MutableStore from 'store';
3281
- let z = {};
3282
-
3283
- function MyComponent(props) {
3284
- let x = props.foo;
3285
- {
3286
- let y = props.bar;
3287
- useEffect(() => {
3288
- console.log(MutableStore.hello.world, props.foo, x, y, z, global.stuff);
3289
- }, [props.foo, x, y]);
3290
- }
3291
- }
3292
- `,
3293
- errors: [
3294
- 'React Hook useEffect has unnecessary dependencies: ' +
3295
- "'MutableStore.hello.world', 'global.stuff', and 'z'. " +
3296
- 'Either exclude them or remove the dependency array. ' +
3297
- "Outer scope values like 'MutableStore.hello.world' aren't valid dependencies " +
3298
- "because mutating them doesn't re-render the component.",
3299
- ],
3300
- },
3301
- {
3302
- code: `
4049
+ errors: [
4050
+ {
4051
+ message:
4052
+ 'React Hook useEffect has unnecessary dependencies: ' +
4053
+ "'MutableStore.hello.world', 'global.stuff', and 'z'. " +
4054
+ 'Either exclude them or remove the dependency array. ' +
4055
+ "Outer scope values like 'MutableStore.hello.world' aren't valid dependencies " +
4056
+ "because mutating them doesn't re-render the component.",
4057
+ suggestions: [
4058
+ {
4059
+ desc: 'Update the dependencies array to be: [props.foo, x, y]',
4060
+ output: normalizeIndent`
4061
+ import MutableStore from 'store';
4062
+ let z = {};
4063
+
4064
+ function MyComponent(props) {
4065
+ let x = props.foo;
4066
+ {
4067
+ let y = props.bar;
4068
+ useEffect(() => {
4069
+ console.log(MutableStore.hello.world, props.foo, x, y, z, global.stuff);
4070
+ }, [props.foo, x, y]);
4071
+ }
4072
+ }
4073
+ `,
4074
+ },
4075
+ ],
4076
+ },
4077
+ ],
4078
+ },
4079
+ {
4080
+ code: normalizeIndent`
4081
import MutableStore from 'store';
4082
let z = {};
4083
@@ -3313,32 +4091,40 @@ const tests = {
4091
}
4092
}
4093
`,
3316
- // The output should contain the ones that are inside a component
3317
- // since there are legit reasons to over-specify them for effects.
3318
- output: `
3319
- import MutableStore from 'store';
3320
- let z = {};
3321
-
3322
- function MyComponent(props) {
3323
- let x = props.foo;
3324
- {
3325
- let y = props.bar;
3326
- useEffect(() => {
3327
- // nothing
3328
- }, [props.foo, x, y]);
3329
- }
3330
- }
3331
- `,
4094
errors: [
3333
- 'React Hook useEffect has unnecessary dependencies: ' +
3334
- "'MutableStore.hello.world', 'global.stuff', and 'z'. " +
3335
- 'Either exclude them or remove the dependency array. ' +
3336
- "Outer scope values like 'MutableStore.hello.world' aren't valid dependencies " +
3337
- "because mutating them doesn't re-render the component.",
4095
+ {
4096
+ message:
4097
+ 'React Hook useEffect has unnecessary dependencies: ' +
4098
+ "'MutableStore.hello.world', 'global.stuff', and 'z'. " +
4099
+ 'Either exclude them or remove the dependency array. ' +
4100
+ "Outer scope values like 'MutableStore.hello.world' aren't valid dependencies " +
4101
+ "because mutating them doesn't re-render the component.",
4102
+ // The output should contain the ones that are inside a component
4103
+ // since there are legit reasons to over-specify them for effects.
4104
+ suggestions: [
4105
+ {
4106
+ desc: 'Update the dependencies array to be: [props.foo, x, y]',
4107
+ output: normalizeIndent`
4108
+ import MutableStore from 'store';
4109
+ let z = {};
4110
+
4111
+ function MyComponent(props) {
4112
+ let x = props.foo;
4113
+ {
4114
+ let y = props.bar;
4115
+ useEffect(() => {
4116
+ // nothing
4117
+ }, [props.foo, x, y]);
4118
+ }
4119
+ }
4120
+ `,
4121
+ },
4122
+ ],
4123
+ },
4124
],
4125
},
4126
{
3341
- code: `
4127
+ code: normalizeIndent`
4128
import MutableStore from 'store';
4129
let z = {};
4130
@@ -3352,31 +4138,39 @@ const tests = {
4138
}
4139
}
4140
`,
3355
- output: `
3356
- import MutableStore from 'store';
3357
- let z = {};
3358
-
3359
- function MyComponent(props) {
3360
- let x = props.foo;
3361
- {
3362
- let y = props.bar;
3363
- const fn = useCallback(() => {
3364
- // nothing
3365
- }, []);
3366
- }
3367
- }
3368
- `,
4141
errors: [
3370
- 'React Hook useCallback has unnecessary dependencies: ' +
3371
- "'MutableStore.hello.world', 'global.stuff', 'props.foo', 'x', 'y', and 'z'. " +
3372
- 'Either exclude them or remove the dependency array. ' +
3373
- "Outer scope values like 'MutableStore.hello.world' aren't valid dependencies " +
3374
- "because mutating them doesn't re-render the component.",
4142
+ {
4143
+ message:
4144
+ 'React Hook useCallback has unnecessary dependencies: ' +
4145
+ "'MutableStore.hello.world', 'global.stuff', 'props.foo', 'x', 'y', and 'z'. " +
4146
+ 'Either exclude them or remove the dependency array. ' +
4147
+ "Outer scope values like 'MutableStore.hello.world' aren't valid dependencies " +
4148
+ "because mutating them doesn't re-render the component.",
4149
+ suggestions: [
4150
+ {
4151
+ desc: 'Update the dependencies array to be: []',
4152
+ output: normalizeIndent`
4153
+ import MutableStore from 'store';
4154
+ let z = {};
4155
+
4156
+ function MyComponent(props) {
4157
+ let x = props.foo;
4158
+ {
4159
+ let y = props.bar;
4160
+ const fn = useCallback(() => {
4161
+ // nothing
4162
+ }, []);
4163
+ }
4164
+ }
4165
+ `,
4166
+ },
4167
+ ],
4168
+ },
4169
],
4170
},
4171
{
4172
// Every almost-static function is tainted by a dynamic value.
3379
- code: `
4173
+ code: normalizeIndent`
4174
function MyComponent(props) {
4175
let [, setState] = useState();
4176
let [, dispatch] = React.useReducer();
@@ -3406,48 +4200,132 @@ const tests = {
4200
}, []);
4201
}
4202
`,
3409
- output: `
3410
- function MyComponent(props) {
3411
- let [, setState] = useState();
3412
- let [, dispatch] = React.useReducer();
3413
- let taint = props.foo;
3414
-
3415
- function handleNext1(value) {
3416
- let value2 = value * taint;
3417
- setState(value2);
3418
- console.log('hello');
3419
- }
3420
- const handleNext2 = (value) => {
3421
- setState(taint(value));
3422
- console.log('hello');
3423
- };
3424
- let handleNext3 = function(value) {
3425
- setTimeout(() => console.log(taint));
3426
- dispatch({ type: 'x', value });
3427
- };
3428
- useEffect(() => {
3429
- return Store.subscribe(handleNext1);
3430
- }, [handleNext1]);
3431
- useLayoutEffect(() => {
3432
- return Store.subscribe(handleNext2);
3433
- }, [handleNext2]);
3434
- useMemo(() => {
3435
- return Store.subscribe(handleNext3);
3436
- }, [handleNext3]);
3437
- }
3438
- `,
4203
errors: [
3440
- "React Hook useEffect has a missing dependency: 'handleNext1'. " +
3441
- 'Either include it or remove the dependency array.',
3442
- "React Hook useLayoutEffect has a missing dependency: 'handleNext2'. " +
3443
- 'Either include it or remove the dependency array.',
3444
- "React Hook useMemo has a missing dependency: 'handleNext3'. " +
3445
- 'Either include it or remove the dependency array.',
4204
+ {
4205
+ message:
4206
+ "React Hook useEffect has a missing dependency: 'handleNext1'. " +
4207
+ 'Either include it or remove the dependency array.',
4208
+ suggestions: [
4209
+ {
4210
+ desc: 'Update the dependencies array to be: [handleNext1]',
4211
+ output: normalizeIndent`
4212
+ function MyComponent(props) {
4213
+ let [, setState] = useState();
4214
+ let [, dispatch] = React.useReducer();
4215
+ let taint = props.foo;
4216
+
4217
+ function handleNext1(value) {
4218
+ let value2 = value * taint;
4219
+ setState(value2);
4220
+ console.log('hello');
4221
+ }
4222
+ const handleNext2 = (value) => {
4223
+ setState(taint(value));
4224
+ console.log('hello');
4225
+ };
4226
+ let handleNext3 = function(value) {
4227
+ setTimeout(() => console.log(taint));
4228
+ dispatch({ type: 'x', value });
4229
+ };
4230
+ useEffect(() => {
4231
+ return Store.subscribe(handleNext1);
4232
+ }, [handleNext1]);
4233
+ useLayoutEffect(() => {
4234
+ return Store.subscribe(handleNext2);
4235
+ }, []);
4236
+ useMemo(() => {
4237
+ return Store.subscribe(handleNext3);
4238
+ }, []);
4239
+ }
4240
+ `,
4241
+ },
4242
+ ],
4243
+ },
4244
+ {
4245
+ message:
4246
+ "React Hook useLayoutEffect has a missing dependency: 'handleNext2'. " +
4247
+ 'Either include it or remove the dependency array.',
4248
+ suggestions: [
4249
+ {
4250
+ desc: 'Update the dependencies array to be: [handleNext2]',
4251
+ output: normalizeIndent`
4252
+ function MyComponent(props) {
4253
+ let [, setState] = useState();
4254
+ let [, dispatch] = React.useReducer();
4255
+ let taint = props.foo;
4256
+
4257
+ function handleNext1(value) {
4258
+ let value2 = value * taint;
4259
+ setState(value2);
4260
+ console.log('hello');
4261
+ }
4262
+ const handleNext2 = (value) => {
4263
+ setState(taint(value));
4264
+ console.log('hello');
4265
+ };
4266
+ let handleNext3 = function(value) {
4267
+ setTimeout(() => console.log(taint));
4268
+ dispatch({ type: 'x', value });
4269
+ };
4270
+ useEffect(() => {
4271
+ return Store.subscribe(handleNext1);
4272
+ }, []);
4273
+ useLayoutEffect(() => {
4274
+ return Store.subscribe(handleNext2);
4275
+ }, [handleNext2]);
4276
+ useMemo(() => {
4277
+ return Store.subscribe(handleNext3);
4278
+ }, []);
4279
+ }
4280
+ `,
4281
+ },
4282
+ ],
4283
+ },
4284
+ {
4285
+ message:
4286
+ "React Hook useMemo has a missing dependency: 'handleNext3'. " +
4287
+ 'Either include it or remove the dependency array.',
4288
+ suggestions: [
4289
+ {
4290
+ desc: 'Update the dependencies array to be: [handleNext3]',
4291
+ output: normalizeIndent`
4292
+ function MyComponent(props) {
4293
+ let [, setState] = useState();
4294
+ let [, dispatch] = React.useReducer();
4295
+ let taint = props.foo;
4296
+
4297
+ function handleNext1(value) {
4298
+ let value2 = value * taint;
4299
+ setState(value2);
4300
+ console.log('hello');
4301
+ }
4302
+ const handleNext2 = (value) => {
4303
+ setState(taint(value));
4304
+ console.log('hello');
4305
+ };
4306
+ let handleNext3 = function(value) {
4307
+ setTimeout(() => console.log(taint));
4308
+ dispatch({ type: 'x', value });
4309
+ };
4310
+ useEffect(() => {
4311
+ return Store.subscribe(handleNext1);
4312
+ }, []);
4313
+ useLayoutEffect(() => {
4314
+ return Store.subscribe(handleNext2);
4315
+ }, []);
4316
+ useMemo(() => {
4317
+ return Store.subscribe(handleNext3);
4318
+ }, [handleNext3]);
4319
+ }
4320
+ `,
4321
+ },
4322
+ ],
4323
+ },
4324
],
4325
},
4326
{
4327
// Regression test
3450
- code: `
4328
+ code: normalizeIndent`
4329
function MyComponent(props) {
4330
let [, setState] = useState();
4331
let [, dispatch] = React.useReducer();
@@ -3480,51 +4358,141 @@ const tests = {
4358
}, []);
4359
}
4360
`,
3483
- output: `
3484
- function MyComponent(props) {
3485
- let [, setState] = useState();
3486
- let [, dispatch] = React.useReducer();
3487
- let taint = props.foo;
4361
+ errors: [
4362
+ {
4363
+ message:
4364
+ "React Hook useEffect has a missing dependency: 'handleNext1'. " +
4365
+ 'Either include it or remove the dependency array.',
4366
+ suggestions: [
4367
+ {
4368
+ desc: 'Update the dependencies array to be: [handleNext1]',
4369
+ output: normalizeIndent`
4370
+ function MyComponent(props) {
4371
+ let [, setState] = useState();
4372
+ let [, dispatch] = React.useReducer();
4373
+ let taint = props.foo;
4374
3489
- // Shouldn't affect anything
3490
- function handleChange() {}
4375
+ // Shouldn't affect anything
4376
+ function handleChange() {}
4377
3492
- function handleNext1(value) {
3493
- let value2 = value * taint;
3494
- setState(value2);
3495
- console.log('hello');
3496
- }
3497
- const handleNext2 = (value) => {
3498
- setState(taint(value));
3499
- console.log('hello');
3500
- };
3501
- let handleNext3 = function(value) {
3502
- console.log(taint);
3503
- dispatch({ type: 'x', value });
3504
- };
3505
- useEffect(() => {
3506
- return Store.subscribe(handleNext1);
3507
- }, [handleNext1]);
3508
- useLayoutEffect(() => {
3509
- return Store.subscribe(handleNext2);
3510
- }, [handleNext2]);
3511
- useMemo(() => {
3512
- return Store.subscribe(handleNext3);
3513
- }, [handleNext3]);
3514
- }
3515
- `,
3516
- errors: [
3517
- "React Hook useEffect has a missing dependency: 'handleNext1'. " +
3518
- 'Either include it or remove the dependency array.',
3519
- "React Hook useLayoutEffect has a missing dependency: 'handleNext2'. " +
3520
- 'Either include it or remove the dependency array.',
3521
- "React Hook useMemo has a missing dependency: 'handleNext3'. " +
3522
- 'Either include it or remove the dependency array.',
4378
+ function handleNext1(value) {
4379
+ let value2 = value * taint;
4380
+ setState(value2);
4381
+ console.log('hello');
4382
+ }
4383
+ const handleNext2 = (value) => {
This file is too large to show in full.
packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js
+53
-30
@@ -11,7 +11,6 @@
11
12
export default {
13
meta: {
14
- fixable: 'code',
14
schema: [
15
{
16
type: 'object',
@@ -94,7 +93,7 @@ export default {
93
reactiveHookName === 'useMemo' ||
94
reactiveHookName === 'useCallback'
95
) {
97
- // TODO: Can this have an autofix?
96
+ // TODO: Can this have a suggestion?
97
context.report({
98
node: node.parent.callee,
99
message:
@@ -558,12 +557,19 @@ export default {
557
`To fix this, pass [` +
558
suggestedDependencies.join(', ') +
559
`] as a second argument to the ${reactiveHookName} Hook.`,
561
- fix(fixer) {
562
- return fixer.insertTextAfter(
563
- node,
564
- `, [${suggestedDependencies.join(', ')}]`,
565
- );
566
- },
560
+ suggest: [
561
+ {
562
+ desc: `Add dependencies array: [${suggestedDependencies.join(
563
+ ', ',
564
+ )}]`,
565
+ fix(fixer) {
566
+ return fixer.insertTextAfter(
567
+ node,
568
+ `, [${suggestedDependencies.join(', ')}]`,
569
+ );
570
+ },
571
+ },
572
+ ],
573
});
574
}
575
return;
@@ -702,27 +708,37 @@ export default {
708
` Move it inside the ${reactiveHookName} callback. ` +
709
`Alternatively, wrap the '${fn.name.name}' definition into its own useCallback() Hook.`;
710
}
711
+
712
+ let suggest;
713
+ // Only handle the simple case: arrow functions.
714
+ // Wrapping function declarations can mess up hoisting.
715
+ if (suggestUseCallback && fn.type === 'Variable') {
716
+ suggest = [
717
+ {
718
+ desc: `Wrap the '${
719
+ fn.name.name
720
+ }' definition into its own useCallback() Hook.`,
721
+ fix(fixer) {
722
+ return [
723
+ // TODO: also add an import?
724
+ fixer.insertTextBefore(fn.node.init, 'useCallback('),
725
+ // TODO: ideally we'd gather deps here but it would require
726
+ // restructuring the rule code. This will cause a new lint
727
+ // error to appear immediately for useCallback. Note we're
728
+ // not adding [] because would that changes semantics.
729
+ fixer.insertTextAfter(fn.node.init, ')'),
730
+ ];
731
+ },
732
+ },
733
+ ];
734
+ }
735
// TODO: What if the function needs to change on every render anyway?
736
// Should we suggest removing effect deps as an appropriate fix too?
737
context.report({
738
// TODO: Why not report this at the dependency site?
739
node: fn.node,
740
message,
711
- fix(fixer) {
712
- // Only handle the simple case: arrow functions.
713
- // Wrapping function declarations can mess up hoisting.
714
- if (suggestUseCallback && fn.type === 'Variable') {
715
- return [
716
- // TODO: also add an import?
717
- fixer.insertTextBefore(fn.node.init, 'useCallback('),
718
- // TODO: ideally we'd gather deps here but it would require
719
- // restructuring the rule code. This will cause a new lint
720
- // error to appear immediately for useCallback. Note we're
721
- // not adding [] because would that changes semantics.
722
- fixer.insertTextAfter(fn.node.init, ')'),
723
- ];
724
- }
725
- },
741
+ suggest,
742
});
743
});
744
return;
@@ -1008,13 +1024,20 @@ export default {
1024
'omit',
1025
)) +
1026
extraWarning,
1011
- fix(fixer) {
1012
- // TODO: consider preserving the comments or formatting?
1013
- return fixer.replaceText(
1014
- declaredDependenciesNode,
1015
- `[${suggestedDependencies.join(', ')}]`,
1016
- );
1017
- },
1027
+ suggest: [
1028
+ {
1029
+ desc: `Update the dependencies array to be: [${suggestedDependencies.join(
1030
+ ', ',
1031
+ )}]`,
1032
+ fix(fixer) {
1033
+ // TODO: consider preserving the comments or formatting?
1034
+ return fixer.replaceText(
1035
+ declaredDependenciesNode,
1036
+ `[${suggestedDependencies.join(', ')}]`,
1037
+ );
1038
+ },
1039
+ },
1040
+ ],
1041
});
1042
}
1043
},