@samitouri / QOS-React-2 / commits / 7118f5dd7b

[ESLint] Disallow hooks in async functions (#27045)

Hooks cannot be called in async functions, on either the client or the server. This mistake sometimes happens when using Server Components, especially when refactoring a Server Component to a Client Component. React logs a warning at runtime, but it's even better to catch this with a lint rule since it will show immediate inline feedback in the editor. I added this to the existing "Rules of Hooks" ESLint rule.

Andrew Clark committed Jul 5, 2023 at 11:44 UTC 7118f5dd7bf5f1c44d0d2944ef8ad58e423909ad
2 files changed +41
packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js
+30
@@ -1042,6 +1042,22 @@ const tests = {
1042 `,
1043 errors: [classError('useState')],
1044 },
1045 + {
1046 + code: normalizeIndent`
1047 + async function AsyncComponent() {
1048 + useState();
1049 + }
1050 + `,
1051 + errors: [asyncComponentHookError('useState')],
1052 + },
1053 + {
1054 + code: normalizeIndent`
1055 + async function useAsyncHook() {
1056 + useState();
1057 + }
1058 + `,
1059 + errors: [asyncComponentHookError('useState')],
1060 + },
1061 ],
1062 };
1063
@@ -1300,6 +1316,14 @@ if (__EXPERIMENTAL__) {
1316 `,
1317 errors: [classError('use')],
1318 },
1319 + {
1320 + code: normalizeIndent`
1321 + async function AsyncComponent() {
1322 + use();
1323 + }
1324 + `,
1325 + errors: [asyncComponentHookError('use')],
1326 + },
1327 ];
1328 }
1329
@@ -1368,6 +1392,12 @@ function useEffectEventError(fn) {
1392 };
1393 }
1394
1395 +function asyncComponentHookError(fn) {
1396 + return {
1397 + message: `React Hook "${fn}" cannot be called in an async function.`,
1398 + };
1399 +}
1400 +
1401 // For easier local testing
1402 if (!process.env.CI) {
1403 let only = [];
packages/eslint-plugin-react-hooks/src/RulesOfHooks.js
+11
@@ -485,6 +485,17 @@ export default {
485 // Pick a special message depending on the scope this hook was
486 // called in.
487 if (isDirectlyInsideComponentOrHook) {
488 + // Report an error if the hook is called inside an async function.
489 + const isAsyncFunction = codePathNode.async;
490 + if (isAsyncFunction) {
491 + context.report({
492 + node: hook,
493 + message:
494 + `React Hook "${context.getSource(hook)}" cannot be ` +
495 + 'called in an async function.',
496 + });
497 + }
498 +
499 // Report an error if a hook does not reach all finalizing code
500 // path segments.
501 //