TSLint Rules of Hooks
A TSLint rule that enforces the Rules of Hooks for React hooks.
The rule is based on an ESLint plugin for react hooks.
Features
- detects using React hooks inside potentially-conditional branches:
- if statements
- short-circuit conditional expressions (
&&
,||
) - ternary expressions
- loops (
while
,for
,do ... while
) - functions that themselves are not custom hooks or components
Installation
First, install the rule:
npm install tslint-react-hooks --save-dev
Then, enable the rule by modifying tslint.json
:
{
"extends": [
// your other plugins...
"tslint-react-hooks"
],
"rules": {
// your other rules...
"react-hooks-nesting": "error"
}
}
To use report rule violations as warnings intead of errors, set it to "warning"
.
False positives and not-covered cases
There are some cases that seem hard to analyze and may result in false positives or false negatives.
In such cases, disable the rule for a specific line using the following comment:
// tslint:disable:react-hooks-nesting
useEffect(() => {});
Looping over static arrays
The rule may report false positives, for example in:
function MyComponent() {
const array = [1, 2, 3];
array.forEach(value => {
React.useEffect(() => console.log(value));
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [A hook cannot be used inside of another function]
});
}
The useEffect
hook will be called unconditionally and the call-order will be the same between
renders.
Using renamed hooks (that do not start with use)
The rule only treats functions that start with use as hooks. Therefore, renaming the hook will
result in avoiding the rule:
const renamedUseState = React.useState;
function MyComponent() {
const [state, setState] = renamedUseState(0);
}
Unconditional nesting
Unconditional nesting, for example:
function MyComponent() {
if (true) {
const variableThatCannotBeLeaked = useContext(SomeContext);
useEffect(() => {
console.log(variableThatCannotBeLeaked);
});
}
return <div>Text</div>;
}
is treated as conditional nesting. It seems hard to verify if the condition is in fact a constant,
therefore such a situation will always result in a rule violation.
In situations where such an if
statement was used to create an additional block scope, use the
block scope directly:
function MyComponent() {
{
const variableThatCannotBeLeaked = useContext(SomeContext);
useEffect(() => {
console.log(variableThatCannotBeLeaked);
});
}
return <div>Text</div>;
}
Development
After pulling the repository, make sure to run
npm install
The source code for the rule is located in the src
directory.
For more information about the developing custom TSLint rules, take a look at
TSLint's documentation.
Testing the rule
Run
npm run test
to compile the rule and run automatic TSLint tests.
They are located in the test
directory.