mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[eslint] Disallow use within try/catch blocks (#34040)
Follow up to #34032. The linter now ensures that `use` cannot be used within try/catch.
This commit is contained in:
@@ -1324,6 +1324,34 @@ const allTests = {
|
||||
`,
|
||||
errors: [asyncComponentHookError('use')],
|
||||
},
|
||||
{
|
||||
code: normalizeIndent`
|
||||
function App({p1, p2}) {
|
||||
try {
|
||||
use(p1);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
use(p2);
|
||||
return <div>App</div>;
|
||||
}
|
||||
`,
|
||||
errors: [tryCatchUseError('use')],
|
||||
},
|
||||
{
|
||||
code: normalizeIndent`
|
||||
function App({p1, p2}) {
|
||||
try {
|
||||
doSomething();
|
||||
} catch {
|
||||
use(p1);
|
||||
}
|
||||
use(p2);
|
||||
return <div>App</div>;
|
||||
}
|
||||
`,
|
||||
errors: [tryCatchUseError('use')],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@@ -1383,7 +1411,7 @@ if (__EXPERIMENTAL__) {
|
||||
const onEvent = useEffectEvent((text) => {
|
||||
console.log(text);
|
||||
});
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
onEvent('Hello world');
|
||||
});
|
||||
@@ -1421,7 +1449,7 @@ if (__EXPERIMENTAL__) {
|
||||
});
|
||||
return <Child onClick={() => onClick()} />
|
||||
}
|
||||
|
||||
|
||||
// The useEffectEvent function shares an identifier name with the above
|
||||
function MyLastComponent({theme}) {
|
||||
const onClick = useEffectEvent(() => {
|
||||
@@ -1573,6 +1601,12 @@ function asyncComponentHookError(fn) {
|
||||
};
|
||||
}
|
||||
|
||||
function tryCatchUseError(fn) {
|
||||
return {
|
||||
message: `React Hook "${fn}" cannot be called in a try/catch block.`,
|
||||
};
|
||||
}
|
||||
|
||||
// For easier local testing
|
||||
if (!process.env.CI) {
|
||||
let only = [];
|
||||
|
||||
@@ -7,7 +7,13 @@
|
||||
/* eslint-disable no-for-of-loops/no-for-of-loops */
|
||||
|
||||
import type {Rule, Scope} from 'eslint';
|
||||
import type {CallExpression, DoWhileStatement, Node} from 'estree';
|
||||
import type {
|
||||
CallExpression,
|
||||
CatchClause,
|
||||
DoWhileStatement,
|
||||
Node,
|
||||
TryStatement,
|
||||
} from 'estree';
|
||||
|
||||
// @ts-expect-error untyped module
|
||||
import CodePathAnalyzer from '../code-path-analysis/code-path-analyzer';
|
||||
@@ -111,6 +117,18 @@ function isInsideDoWhileLoop(node: Node | undefined): node is DoWhileStatement {
|
||||
return false;
|
||||
}
|
||||
|
||||
function isInsideTryCatch(
|
||||
node: Node | undefined,
|
||||
): node is TryStatement | CatchClause {
|
||||
while (node) {
|
||||
if (node.type === 'TryStatement' || node.type === 'CatchClause') {
|
||||
return true;
|
||||
}
|
||||
node = node.parent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isUseEffectEventIdentifier(node: Node): boolean {
|
||||
if (__EXPERIMENTAL__) {
|
||||
return node.type === 'Identifier' && node.name === 'useEffectEvent';
|
||||
@@ -532,6 +550,16 @@ const rule = {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Report an error if use() is called inside try/catch.
|
||||
if (isUseIdentifier(hook) && isInsideTryCatch(hook)) {
|
||||
context.report({
|
||||
node: hook,
|
||||
message: `React Hook "${getSourceCode().getText(
|
||||
hook,
|
||||
)}" cannot be called in a try/catch block.`,
|
||||
});
|
||||
}
|
||||
|
||||
// Report an error if a hook may be called more then once.
|
||||
// `use(...)` can be called in loops.
|
||||
if (
|
||||
|
||||
Reference in New Issue
Block a user