It would be great to have a rule to enforce the standard naming convention for useState():
const [x, setX] = useState(...)
For example, the rule would consider this an error:
const [x, setFoo] = useState(...)
This would ensure that all useState variables followed the same convention, i.e. ${varName} and set${upperFirstVarName}.
This seems like a better rule for eslint-plugin-react-hooks.
@ljharb I read somewhere that eslint-plugin-react-hooks deliberately avoids including stylistic rules, and intends to focus only on behavioral things, i.e. "rules of hooks". But maybe they would be open to adding this stylistic rule if it were disabled by default...I could open an issue there and see what they say.
@ljharb Would the eslint-plugin-react project be opposed to adding this feature?
Seems like the issue in facebook/react to add it to eslint-plugin-react-hooks got no response and was autoclosed by the bot...
I'd love to see it go into eslint-plugin-react-hooks if possible.
Ok, @mbrowne opened a new PR at facebook/react, let's see if it gets any traction: https://github.com/facebook/react/issues/19883
So gaearon confirmed in https://github.com/facebook/react/issues/19883#issuecomment-722059542:
We won't be focusing on stylistic enforcement like this in the official plugin. This is definitely welcome in the ecosystem, but the official plugin focuses on correctness rather than style or naming.
@ljharb would a pull request be welcome in eslint-plugin-react?
Is there a way the âhook detectionâ code could be shared between the two? I donât want this plugin to have to reinvent it, and then risk deviating from it in the future.
Maybe depending on eslint-plugin-react-hooks and then somehow using the isHook and isHookName functions?
Unfortunately they are not exported, but depending on the willingness of @gaearon to expose them and the value of sharing this code, I guess the file could be patched using patch-package or similar...
Hopefully they can either be exported, or published as a separate package that both consume. @gaearon?
Actually, looking into this a bit more, I guess the code that would be shared would be low (just the single-line regex). And - we probably could just match only the literal string 'useState', since this rule will only apply to this hook.
So maybe we don't need to export the code.
I am a beginner at writing ESLint plugins, but I've put together something as a proof of concept that we probably wouldn't need to share code on AST explorer. The only thing specific to React Hooks here is the one string "useState".
Thoughts @ljharb ?
function MyComponent() {
const [a, set_A] = useState();
const [x, setFoo] = useState('abc');
const [c, d] = [1,2];
}
export default {
meta: {
messages: {
useStateNaming:
"Identifier '{{name}}' does not follow useState naming convention.",
},
},
create(context) {
return {
Identifier(node) {
if (
node.parent &&
node.parent.type === "ArrayPattern" &&
node.parent.parent &&
node.parent.parent.type === "VariableDeclarator" &&
node.parent.parent.init &&
node.parent.parent.init.callee &&
node.parent.parent.init.callee.name === "useState" &&
node.parent.parent.parent &&
node.parent.parent.parent.type === "VariableDeclaration"
) {
context.report({
node,
messageId: "useStateNaming",
data: { name: node.name },
});
}
},
};
},
};
// Identifier 'a' does not follow useState naming convention. (at 2:10)
const [a, set_A] = useState();
// ---------^
// Identifier 'set_A' does not follow useState naming convention. (at 2:13)
const [a, set_A] = useState();
// ------------^
// Identifier 'x' does not follow useState naming convention. (at 3:10)
const [x, setFoo] = useState('abc');
// ---------^
// Identifier 'setFoo' does not follow useState naming convention. (at 3:13)
const [x, setFoo] = useState('abc');
// ------------^
One downside that I can think of is that this will also check code outside of React components.
But I guess a recursive check through all parents to check whether their Identifier names start with capital letters is also not too much code.
We have component detection logic, so you should be able to only warn inside functional components.
Also, note that someone could rename useState to anything else, so we have to follow any renames or assignments.
Also, note that someone could rename useState to anything else, so we have to follow any renames or assignments.
Oh... I think the official plugin does not support this.
Gut feel says this seems like a nightmare to implement (I guess that's why the official plugin doesn't do it either) - or maybe you have a clear idea of how to traverse the AST to do this easily?
We have component detection logic
Ah that sounds great. Would you be open to me starting on a PR for this with my rudimentary AST / ESLint API skills? đ I may need some guidance...!
Opening a draft PR sounds great. eslint provides some utilities for tracking variable renames; weâd have to research whatâs available.
We have component detection logic, so you should be able to only warn inside functional components.
Hooks are used outside of functional components; for example, when writing a custom hook.
Hooks are used outside of functional components; for example, when writing a custom hook.
Ah, good catch!
And thanks for the PR at #2873, looking pretty good!