File tree Expand file tree Collapse file tree 2 files changed +65
-3
lines changed
packages/eslint-plugin-react-hooks Expand file tree Collapse file tree 2 files changed +65
-3
lines changed Original file line number Diff line number Diff line change @@ -1324,6 +1324,34 @@ const allTests = {
13241324 ` ,
13251325 errors : [ asyncComponentHookError ( 'use' ) ] ,
13261326 } ,
1327+ {
1328+ code : normalizeIndent `
1329+ function App({p1, p2}) {
1330+ try {
1331+ use(p1);
1332+ } catch (error) {
1333+ console.error(error);
1334+ }
1335+ use(p2);
1336+ return <div>App</div>;
1337+ }
1338+ ` ,
1339+ errors : [ tryCatchUseError ( 'use' ) ] ,
1340+ } ,
1341+ {
1342+ code : normalizeIndent `
1343+ function App({p1, p2}) {
1344+ try {
1345+ doSomething();
1346+ } catch {
1347+ use(p1);
1348+ }
1349+ use(p2);
1350+ return <div>App</div>;
1351+ }
1352+ ` ,
1353+ errors : [ tryCatchUseError ( 'use' ) ] ,
1354+ } ,
13271355 ] ,
13281356} ;
13291357
@@ -1383,7 +1411,7 @@ if (__EXPERIMENTAL__) {
13831411 const onEvent = useEffectEvent((text) => {
13841412 console.log(text);
13851413 });
1386-
1414+
13871415 useEffect(() => {
13881416 onEvent('Hello world');
13891417 });
@@ -1421,7 +1449,7 @@ if (__EXPERIMENTAL__) {
14211449 });
14221450 return <Child onClick={() => onClick()} />
14231451 }
1424-
1452+
14251453 // The useEffectEvent function shares an identifier name with the above
14261454 function MyLastComponent({theme}) {
14271455 const onClick = useEffectEvent(() => {
@@ -1573,6 +1601,12 @@ function asyncComponentHookError(fn) {
15731601 } ;
15741602}
15751603
1604+ function tryCatchUseError ( fn ) {
1605+ return {
1606+ message : `React Hook "${ fn } " cannot be called in a try/catch block.` ,
1607+ } ;
1608+ }
1609+
15761610// For easier local testing
15771611if ( ! process . env . CI ) {
15781612 let only = [ ] ;
Original file line number Diff line number Diff line change 77/* eslint-disable no-for-of-loops/no-for-of-loops */
88
99import type { Rule , Scope } from 'eslint' ;
10- import type { CallExpression , DoWhileStatement , Node } from 'estree' ;
10+ import type {
11+ CallExpression ,
12+ CatchClause ,
13+ DoWhileStatement ,
14+ Node ,
15+ TryStatement ,
16+ } from 'estree' ;
1117
1218// @ts -expect-error untyped module
1319import CodePathAnalyzer from '../code-path-analysis/code-path-analyzer' ;
@@ -111,6 +117,18 @@ function isInsideDoWhileLoop(node: Node | undefined): node is DoWhileStatement {
111117 return false ;
112118}
113119
120+ function isInsideTryCatch (
121+ node : Node | undefined ,
122+ ) : node is TryStatement | CatchClause {
123+ while ( node ) {
124+ if ( node . type === 'TryStatement' || node . type === 'CatchClause' ) {
125+ return true ;
126+ }
127+ node = node . parent ;
128+ }
129+ return false ;
130+ }
131+
114132function isUseEffectEventIdentifier ( node : Node ) : boolean {
115133 if ( __EXPERIMENTAL__ ) {
116134 return node . type === 'Identifier' && node . name === 'useEffectEvent' ;
@@ -532,6 +550,16 @@ const rule = {
532550 continue ;
533551 }
534552
553+ // Report an error if use() is called inside try/catch/finally.
554+ if ( isUseIdentifier ( hook ) && isInsideTryCatch ( hook ) ) {
555+ context . report ( {
556+ node : hook ,
557+ message : `React Hook "${ getSourceCode ( ) . getText (
558+ hook ,
559+ ) } " cannot be called in a try/catch block.`,
560+ } ) ;
561+ }
562+
535563 // Report an error if a hook may be called more then once.
536564 // `use(...)` can be called in loops.
537565 if (
You can’t perform that action at this time.
0 commit comments