mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
react-hooks/rules-of-hooks: Improve support for do/while loops (#31720)
This commit is contained in:
@@ -550,6 +550,18 @@ const tests = {
|
||||
// TODO: this should error but doesn't.
|
||||
// errors: [genericError('useState')],
|
||||
},
|
||||
{
|
||||
code: normalizeIndent`
|
||||
// Valid because the hook is outside of the loop
|
||||
const Component = () => {
|
||||
const [state, setState] = useState(0);
|
||||
for (let i = 0; i < 10; i++) {
|
||||
console.log(i);
|
||||
}
|
||||
return <div></div>;
|
||||
};
|
||||
`,
|
||||
},
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
|
||||
@@ -100,6 +100,16 @@ function isInsideComponentOrHook(node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function isInsideDoWhileLoop(node) {
|
||||
while (node) {
|
||||
if (node.type === 'DoWhileStatement') {
|
||||
return true;
|
||||
}
|
||||
node = node.parent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isUseEffectEventIdentifier(node) {
|
||||
if (__EXPERIMENTAL__) {
|
||||
return node.type === 'Identifier' && node.name === 'useEffectEvent';
|
||||
@@ -295,7 +305,7 @@ export default {
|
||||
if (pathList.has(segment.id)) {
|
||||
const pathArray = Array.from(pathList);
|
||||
const cyclicSegments = pathArray.slice(
|
||||
pathArray.indexOf(segment.id) - 1,
|
||||
pathArray.indexOf(segment.id) + 1,
|
||||
);
|
||||
for (const cyclicSegment of cyclicSegments) {
|
||||
cyclic.add(cyclicSegment);
|
||||
@@ -485,7 +495,10 @@ export default {
|
||||
for (const hook of reactHooks) {
|
||||
// Report an error if a hook may be called more then once.
|
||||
// `use(...)` can be called in loops.
|
||||
if (cycled && !isUseIdentifier(hook)) {
|
||||
if (
|
||||
(cycled || isInsideDoWhileLoop(hook)) &&
|
||||
!isUseIdentifier(hook)
|
||||
) {
|
||||
context.report({
|
||||
node: hook,
|
||||
message:
|
||||
@@ -520,7 +533,8 @@ export default {
|
||||
if (
|
||||
!cycled &&
|
||||
pathsFromStartToEnd !== allPathsFromStartToEnd &&
|
||||
!isUseIdentifier(hook) // `use(...)` can be called conditionally.
|
||||
!isUseIdentifier(hook) && // `use(...)` can be called conditionally.
|
||||
!isInsideDoWhileLoop(hook) // wrapping do/while loops are checked separately.
|
||||
) {
|
||||
const message =
|
||||
`React Hook "${getSource(hook)}" is called ` +
|
||||
|
||||
Reference in New Issue
Block a user