Next.js stability
no-async-useeffect
Disallow `useEffect(async () => …)` — returns a Promise instead of a cleanup.
The single most common AI-generated React antipattern. An async callback returns `Promise<undefined>`, which React does not treat as a cleanup. Subscriptions leak; React 18 Strict Mode's double-invoke produces races that look impossible to reproduce. Wrap the async body in an inner function and call it.
Behavior
- Fixable: No.
- Suggestions: No.
Examples
Bad:
useEffect(async () => { await load(); }, []);Good:
useEffect(() => { (async () => { await load(); })(); }, []);Related rules
no-hydration-mismatchFlag non-deterministic values (`Math.random`, `Date.now`, `new Date()`) inline in JSX.no-leaked-env-on-clientFlag non-public `process.env.X` reads from `"use client"` or `*.client.{ts,tsx}` files.no-floating-promise-handlerRequire try/catch (or an async wrapper) on async Express/Fastify route handlers.
Use it
Enable no-async-useeffect in your eslint.config.js:
import deslint from '@deslint/eslint-plugin';
export default [
{
plugins: { deslint },
rules: {
'deslint/no-async-useeffect': 'error',
},
},
];Found a false positive? Report it on GitHub →