Skip to content

Commit 2bfe443

Browse files
committed
fixup! [New] Symmetric useState hook variable names
1 parent 99fd001 commit 2bfe443

File tree

3 files changed

+116
-34
lines changed

3 files changed

+116
-34
lines changed

docs/rules/hook-use-state.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,29 @@ This rule checks whether the value and setter variables destructured from a `Rea
99
Examples of **incorrect** code for this rule:
1010

1111
```js
12+
import React from 'react';
1213
const useStateResult = React.useState();
1314
```
1415

1516
```js
17+
import { useState } from 'react';
18+
const useStateResult = useState();
19+
```
20+
21+
```js
22+
import React from 'react';
1623
const [color, updateColor] = React.useState();
1724
```
1825

1926
Examples of **correct** code for this rule:
2027

28+
29+
```js
30+
import { useState } from 'react';
31+
const [color, setColor] = useState();
32+
```
33+
2134
```js
35+
import React from 'react';
2236
const [color, setColor] = React.useState();
2337
```

lib/rules/hook-use-state.js

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,24 @@ module.exports = {
3232
},
3333

3434
create(context) {
35+
let isReactImported = false;
36+
let reactUseStateLocal;
37+
3538
return {
3639
CallExpression(node) {
3740
const isReactUseStateCall = (
38-
node.callee.type === 'MemberExpression'
41+
isReactImported
42+
&& node.callee.type === 'MemberExpression'
3943
&& node.callee.object.type === 'Identifier'
4044
&& node.callee.object.name === 'React'
4145
&& node.callee.property.type === 'Identifier'
4246
&& node.callee.property.name === 'useState'
4347
);
4448

4549
const isUseStateCall = (
46-
node.callee.type === 'Identifier'
47-
&& node.callee.name === 'useState'
50+
reactUseStateLocal
51+
&& node.callee.type === 'Identifier'
52+
&& node.callee.name === reactUseStateLocal
4853
);
4954

5055
// Ignore unless this is a useState() or React.useState() call.
@@ -95,6 +100,21 @@ module.exports = {
95100
) : undefined
96101
});
97102
}
103+
},
104+
ImportDeclaration(node) {
105+
isReactImported = node.source.type === 'Literal' && node.source.value === 'react';
106+
const reactUseStateSpecifier = isReactImported
107+
? node.specifiers.find(
108+
(specifier) => (
109+
specifier.type === 'ImportSpecifier'
110+
&& specifier.imported.name === 'useState'
111+
)
112+
)
113+
: undefined;
114+
115+
reactUseStateLocal = reactUseStateSpecifier
116+
? reactUseStateSpecifier.local.name
117+
: undefined;
98118
}
99119
};
100120
}

tests/lib/rules/hook-use-state.js

Lines changed: 79 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -27,142 +27,190 @@ const ruleTester = new RuleTester({
2727
const tests = {
2828
valid: [
2929
{
30-
code: 'const [color, setColor] = useState()'
30+
code: `import { useState } from 'react';
31+
const [color, setColor] = useState()`
3132
},
3233
{
33-
code: 'const [color, setColor] = useState(\'#ffffff\')'
34+
code: `import { useState } from 'react';
35+
const [color, setColor] = useState('#ffffff')`
3436
},
3537
{
36-
code: 'const [color, setColor] = React.useState()'
38+
code: `import { useState } from 'react';
39+
const [color, setColor] = React.useState()`
3740
},
3841
{
39-
code: 'const [color1, setColor1] = useState()'
42+
code: `import { useState } from 'react';
43+
const [color1, setColor1] = useState()`
4044
},
4145
{
42-
code: 'const [color, setColor] = useState<string>()',
46+
code: 'const result = useState()'
47+
},
48+
{
49+
code: `import { useRef } from 'react';
50+
const result = useState()`
51+
},
52+
{
53+
code: 'const result = React.useState()'
54+
},
55+
{
56+
code: `import { useState } from 'react';
57+
const [color, setColor] = useState<string>()`,
4358
parser: parsers.TYPESCRIPT_ESLINT
4459
},
4560
{
46-
code: 'const [color, setColor] = useState<string>(\'#ffffff\')',
61+
code: `import { useState } from 'react';
62+
const [color, setColor] = useState<string>('#ffffff')`,
4763
parser: parsers.TYPESCRIPT_ESLINT
4864
}
4965
].concat(parsers.TS([
5066
{
51-
code: 'const [color, setColor] = useState<string>()',
67+
code: `import { useState } from 'react';
68+
const [color, setColor] = useState<string>()`,
5269
parser: parsers['@TYPESCRIPT_ESLINT']
5370
},
5471
{
55-
code: 'const [color, setColor] = useState<string>(\'#ffffff\')',
72+
code: `import { useState } from 'react';
73+
const [color, setColor] = useState<string>('#ffffff')`,
5674
parser: parsers['@TYPESCRIPT_ESLINT']
5775
}
5876
])
5977
),
6078
invalid: [
6179
{
62-
code: 'useState()',
80+
code: `import { useState } from 'react';
81+
useState()`,
82+
errors: [{
83+
message: 'setState call is not destructured into value + setter pair'
84+
}]
85+
},
86+
{
87+
code: `import { useState as useStateAlternativeName } from 'react';
88+
useStateAlternativeName()`,
6389
errors: [{
6490
message: 'setState call is not destructured into value + setter pair'
6591
}]
6692
},
6793
{
68-
code: 'const result = useState()',
94+
code: `import { useState } from 'react';
95+
const result = useState()`,
6996
errors: [{
7097
message: 'setState call is not destructured into value + setter pair'
7198
}]
7299
},
73100
{
74-
code: 'const result = React.useState()',
101+
code: `import { useState } from 'react';
102+
const result = React.useState()`,
75103
errors: [{
76104
message: 'setState call is not destructured into value + setter pair'
77105
}]
78106
},
79107
{
80-
code: 'const [, , extra1] = useState()',
108+
code: `import { useState } from 'react';
109+
const [, , extra1] = useState()`,
81110
errors: [{
82111
message: 'setState call is not destructured into value + setter pair'
83112
}]
84113
},
85114
{
86-
code: 'const [, setColor] = useState()',
115+
code: `import { useState } from 'react';
116+
const [, setColor] = useState()`,
87117
errors: [{
88118
message: 'setState call is not destructured into value + setter pair'
89119
}]
90120
},
91121
{
92-
code: 'const { color } = useState()',
122+
code: `import { useState } from 'react';
123+
const { color } = useState()`,
93124
errors: [{
94125
message: 'setState call is not destructured into value + setter pair'
95126
}]
96127
},
97128
{
98-
code: 'const [] = useState()',
129+
code: `import { useState } from 'react';
130+
const [] = useState()`,
99131
errors: [{
100132
message: 'setState call is not destructured into value + setter pair'
101133
}]
102134
},
103135
{
104-
code: 'const [, , , ,] = useState()',
136+
code: `import { useState } from 'react';
137+
const [, , , ,] = useState()`,
105138
errors: [{
106139
message: 'setState call is not destructured into value + setter pair'
107140
}]
108141
},
109142
{
110-
code: 'const [color] = useState()',
143+
code: `import { useState } from 'react';
144+
const [color] = useState()`,
111145
errors: [{
112146
message: 'setState call is not destructured into value + setter pair'
113147
}],
114-
output: 'const [color, setColor] = useState()'
148+
output: `import { useState } from 'react';
149+
const [color, setColor] = useState()`
115150
},
116151
{
117-
code: 'const [color, , extra1] = useState()',
152+
code: `import { useState } from 'react';
153+
const [color, , extra1] = useState()`,
118154
errors: [{
119155
message: 'setState call is not destructured into value + setter pair'
120156
}],
121-
output: 'const [color, setColor] = useState()'
157+
output: `import { useState } from 'react';
158+
const [color, setColor] = useState()`
122159
},
123160
{
124-
code: 'const [color, setColor, extra1, extra2, extra3] = useState()',
161+
code: `import { useState } from 'react';
162+
const [color, setColor, extra1, extra2, extra3] = useState()`,
125163
errors: [{
126164
message: 'setState call is not destructured into value + setter pair'
127165
}],
128-
output: 'const [color, setColor] = useState()'
166+
output: `import { useState } from 'react';
167+
const [color, setColor] = useState()`
129168
},
130169
{
131-
code: 'const [, makeColor] = useState()',
170+
code: `import { useState } from 'react';
171+
const [, makeColor] = useState()`,
132172
errors: [{
133173
message: 'setState call is not destructured into value + setter pair'
134174
}]
135175
},
136176
{
137-
code: 'const [color, setFlavor, extraneous] = useState()',
177+
code: `import { useState } from 'react';
178+
const [color, setFlavor, extraneous] = useState()`,
138179
errors: [{
139180
message: 'setState call is not destructured into value + setter pair'
140181
}],
141-
output: 'const [color, setColor] = useState()'
182+
output: `import { useState } from 'react';
183+
const [color, setColor] = useState()`
142184
},
143185
{
144-
code: 'const [color, setFlavor] = useState()',
186+
code: `import { useState } from 'react';
187+
const [color, setFlavor] = useState()`,
145188
errors: [{
146189
message: 'setState call is not destructured into value + setter pair'
147190
}],
148-
output: 'const [color, setColor] = useState()'
191+
output: `import { useState } from 'react';
192+
const [color, setColor] = useState()`
149193
},
150194
{
151-
code: 'const [color, setFlavor] = useState<string>()',
195+
code: `import { useState } from 'react';
196+
const [color, setFlavor] = useState<string>()`,
152197
errors: [{
153198
message: 'setState call is not destructured into value + setter pair'
154199
}],
155-
output: 'const [color, setColor] = useState<string>()',
200+
output: `import { useState } from 'react';
201+
const [color, setColor] = useState<string>()`,
156202
parser: parsers.TYPESCRIPT_ESLINT
157203
}
158204
].concat(
159205
parsers.TS([
160206
{
161-
code: 'const [color, setFlavor] = useState<string>()',
207+
code: `import { useState } from 'react';
208+
const [color, setFlavor] = useState<string>()`,
162209
errors: [{
163210
message: 'setState call is not destructured into value + setter pair'
164211
}],
165-
output: 'const [color, setColor] = useState<string>()',
212+
output: `import { useState } from 'react';
213+
const [color, setColor] = useState<string>()`,
166214
parser: parsers['@TYPESCRIPT_ESLINT']
167215
}
168216
])

0 commit comments

Comments
 (0)