Skip to content

Commit

Permalink
[ESLint] Disallow hooks in async functions (facebook#27045)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
acdlite authored and AndyPengc12 committed Apr 15, 2024
1 parent ce7fcbb commit a9d33a4
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1042,6 +1042,22 @@ const tests = {
`,
errors: [classError('useState')],
},
{
code: normalizeIndent`
async function AsyncComponent() {
useState();
}
`,
errors: [asyncComponentHookError('useState')],
},
{
code: normalizeIndent`
async function useAsyncHook() {
useState();
}
`,
errors: [asyncComponentHookError('useState')],
},
],
};

Expand Down Expand Up @@ -1300,6 +1316,14 @@ if (__EXPERIMENTAL__) {
`,
errors: [classError('use')],
},
{
code: normalizeIndent`
async function AsyncComponent() {
use();
}
`,
errors: [asyncComponentHookError('use')],
},
];
}

Expand Down Expand Up @@ -1368,6 +1392,12 @@ function useEffectEventError(fn) {
};
}

function asyncComponentHookError(fn) {
return {
message: `React Hook "${fn}" cannot be called in an async function.`,
};
}

// For easier local testing
if (!process.env.CI) {
let only = [];
Expand Down
11 changes: 11 additions & 0 deletions packages/eslint-plugin-react-hooks/src/RulesOfHooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,17 @@ export default {
// Pick a special message depending on the scope this hook was
// called in.
if (isDirectlyInsideComponentOrHook) {
// Report an error if the hook is called inside an async function.
const isAsyncFunction = codePathNode.async;
if (isAsyncFunction) {
context.report({
node: hook,
message:
`React Hook "${context.getSource(hook)}" cannot be ` +
'called in an async function.',
});
}

// Report an error if a hook does not reach all finalizing code
// path segments.
//
Expand Down

0 comments on commit a9d33a4

Please sign in to comment.