Back to Biomejs

useHookAtTopLevel

src/content/docs/linter/rules/use-hook-at-top-level.mdx

latest8.1 KB
Original Source

import { Tabs, TabItem } from '@astrojs/starlight/components';

<Tabs> <TabItem label="JSX and TSX" icon="seti:javascript"> ## Summary - Rule available since: `v1.0.0` - Diagnostic Category: [`lint/correctness/useHookAtTopLevel`](/reference/diagnostics#diagnostic-category) - This rule is **recommended**, meaning it is enabled by default. - This rule doesn't have a fix. - The default severity of this rule is [**error**](/reference/diagnostics#error). - This rule belongs to the following domains: - [`react`](/linter/domains#react) - [`next`](/linter/domains#next) - Sources: - Same as [`react-hooks/rules-of-hooks`](https://github.com/facebook/react/blob/main/packages/eslint-plugin-react-hooks/README.md)

How to configure

json
{
	"linter": {
		"rules": {
			"correctness": {
				"useHookAtTopLevel": "error"
			}
		}
	}
}

Description

Enforce that all React hooks are being called from the Top Level component functions.

This rule should be used only in React projects.

To understand why this required see https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

Examples

Invalid

js
function Component1({ a }) {
    if (a == 1) {
        useEffect();
    }
}
<pre class="language-text"><code class="language-text">code-block.js:3:9 <a href="https://biomejs.dev/linter/rules/use-hook-at-top-level">lint/correctness/useHookAtTopLevel</a> ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ <strong><span style="color: Tomato;">✖</span></strong> <span style="color: Tomato;">This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.</span> <strong>1 │ </strong>function Component1(&#123; a &#125;) &#123; <strong>2 │ </strong> if (a == 1) &#123; <strong><span style="color: Tomato;">&gt;</span></strong> <strong>3 │ </strong> useEffect(); <strong> │ </strong> <strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong> <strong>4 │ </strong> &#125; <strong>5 │ </strong>&#125; <strong><span style="color: lightgreen;">ℹ</span></strong> <span style="color: lightgreen;">For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.</span> <strong><span style="color: lightgreen;">ℹ</span></strong> <span style="color: lightgreen;">See https://react.dev/reference/rules/rules-of-hooks</span> </code></pre>
js
function Component1({ a }) {
    if (a != 1) {
        return;
    }

    useEffect();
}
<pre class="language-text"><code class="language-text">code-block.js:6:5 <a href="https://biomejs.dev/linter/rules/use-hook-at-top-level">lint/correctness/useHookAtTopLevel</a> ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ <strong><span style="color: Tomato;">✖</span></strong> <span style="color: Tomato;">This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.</span> <strong>4 │ </strong> &#125; <strong>5 │ </strong> <strong><span style="color: Tomato;">&gt;</span></strong> <strong>6 │ </strong> useEffect(); <strong> │ </strong> <strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong> <strong>7 │ </strong>&#125; <strong>8 │ </strong> <strong><span style="color: lightgreen;">ℹ</span></strong> <span style="color: lightgreen;">Hooks should not be called after an early return.</span> <strong>1 │ </strong>function Component1(&#123; a &#125;) &#123; <strong><span style="color: Tomato;">&gt;</span></strong> <strong>2 │ </strong> if (a != 1) &#123; <strong> │ </strong> <strong><span style="color: Tomato;">&gt;</span></strong> <strong>3 │ </strong> return; <strong> │ </strong> <strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong> <strong>4 │ </strong> &#125; <strong>5 │ </strong> <strong><span style="color: lightgreen;">ℹ</span></strong> <span style="color: lightgreen;">For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.</span> <strong><span style="color: lightgreen;">ℹ</span></strong> <span style="color: lightgreen;">See https://react.dev/reference/rules/rules-of-hooks</span> </code></pre>
js
function notAHook() {
    useEffect();
}
<pre class="language-text"><code class="language-text">code-block.js:2:5 <a href="https://biomejs.dev/linter/rules/use-hook-at-top-level">lint/correctness/useHookAtTopLevel</a> ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ <strong><span style="color: Tomato;">✖</span></strong> <span style="color: Tomato;">This hook is being called from within a function or method that is not a hook or component.</span> <strong>1 │ </strong>function notAHook() &#123; <strong><span style="color: Tomato;">&gt;</span></strong> <strong>2 │ </strong> useEffect(); <strong> │ </strong> <strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong> <strong>3 │ </strong>&#125; <strong>4 │ </strong> <strong><span style="color: lightgreen;">ℹ</span></strong> <span style="color: lightgreen;">Move the hook call into the top level of a hook or component in order to use it.</span> <strong><span style="color: lightgreen;">ℹ</span></strong> <span style="color: lightgreen;">See https://react.dev/reference/rules/rules-of-hooks</span> </code></pre>

Valid

js
function Component1() {
    useEffect();
}
js
test("the hook", () => {
    renderHook(() => useHook());
});
</TabItem> </Tabs>