-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
[New] : Enforce useState hook destructuring and variable naming #2873
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[New] : Enforce useState hook destructuring and variable naming #2873
Conversation
Awesome @duncanbeevers ! I think you've probably put more effort into this than I have up until now - haven't found the time to learn what I would need to in order to tackle this 😬 I think it's looking good 🙌 @ljharb what are your thoughts? |
fd0f854
to
b244528
Compare
52df451
to
355ce77
Compare
const [color, updateColor] = React.useState(); | ||
``` | ||
|
||
Examples of **correct** code for this rule: | ||
|
||
```js | ||
const [color, setColor] = React.useState(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would someone want to configure "set" to make "update" allowed? Should we allow that to be configurable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you seen this a lot before? I haven't seen this pattern before.
I suppose allowing arbitrary configuration of the prefix would be ok though (eg. a setterPrefix
option?) - would allow for flexibility for some teams.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would someone want to configure "set" to make "update" allowed? Should we allow that to be configurable?
Just as the naming of hooks is already opinionated, useXYZ
, all the React docs consistently use [thing, setThing]
.
I think it's best to lean on this convention here.
code: 'const useStateResult = useState()' | ||
}, | ||
{ | ||
code: 'const [, , unused] = useState()' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this seems like it should be an error, but i guess not from this rule
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, in my workflow this issue would be caught by the type system.
This test is intended to indicate the rule's non-opinion around a third argument (and to make sure I didn't throw an error on weird inputs)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is now an error. (not fixable)
code: 'const [, setColor] = useState()' | ||
}, | ||
{ | ||
code: 'const useStateResult = useState()' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about if someone does const [state, setThatState] = useStateResult;
or const state = useStateResult[0]; const setThatState = useStateResult[1];
on the next lines?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This rule only looks for calls to useState
which are directly destructured+assigned;
These intermediate-value forms aren't recognized by this rule.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is now an error as well. (not fixable)
{ | ||
code: 'const [color, setColor] = useState<string>()', | ||
parser: parsers.TYPESCRIPT_ESLINT | ||
}, | ||
{ | ||
code: 'const [color, setColor] = useState<string>(\'#ffffff\')', | ||
parser: parsers.TYPESCRIPT_ESLINT | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's also duplicate these and add parsers['@TYPESCRIPT_ESLINT']
so we can handle the new parser too. grep for parsers.TS(
to find examples of how to do this safely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I added these correctly.
message: 'setState variable names are not symmetric, setter should be setColor' | ||
}], | ||
output: 'const [color, setColor] = useState<string>()', | ||
parser: parsers.TYPESCRIPT_ESLINT |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
duplicate test case with the new parser here too
Ensure two symmetrically-named variables are destructured from useState hook calls
dea7de1
to
80ed3fc
Compare
@ljharb The scope of this rule has increased, and its naming has been changed from As you mentioned in your first review, certain unusual usages of Towards that end of providing gentle, but clear guidance in the usage of this hook+rule, the naming has been changed to It is now a bit more prescriptive, and therefore a bit more helpful in its fix suggestions. Stuff that didn't change
Stuff that changed
// Who does this!?
const [] = useState();
const [, , , , ] = useState(); |
Closing now that the core rule change has landed. |
Oops wrong PR. I'll re-open this one and remove the no-unused-expresssion PR. mea culpa |
Ensure symmetric value and setter variable names are destructured from React.setState hook calls
Towards #2417
@karlhorky feel free to riff on this, or let me know how this compares to your own proof-of-concept.
useState
andReact.useState
useState<>
type annotationuseState
uses like destructuring too many items, or not destructuring at allset<X>
naming convention@ljharb I included this in the
Best Practices
category, though perhaps a different categorization would be more appropriate.Let me know if the documentation needs anything else, like more examples, or whether the laissez-faire approach to weird assignment is too forgiving.