# react-hooks/hooks

> Require hooks to be called at the top level of a component or hook, never conditionally

React tells one `useState` from the next by the order the hooks are called in. That order must be the same on every render. A hook inside an `if`, a loop, or after an early `return` runs on some renders and not on others. Then state ends up with the wrong hook, or React throws.

The rule also reports a hook that's called inside a nested function, and a hook that's passed around as a value instead of being called.

{/* Generated by src/codegen/lint-rule-docs.ts. Do not edit this section. */}

## Configure

Off by default. To turn it on:

```toml bunfig.toml
[lint.rules]
"react-hooks/hooks" = "error" # or "warn"
```

{/* End of the generated section. */}

## Examples

Reported:

{/* bad */}
```jsx
import { useState } from "react";

function Profile({ user }) {
  if (!user) {
    return null;
  }
  const [name, setName] = useState(user.name);
  return <input value={name} onChange={event => setName(event.target.value)} />;
}
```

{/* bad */}
```jsx
import { useState } from "react";

function UserList({ users }) {
  const rows = users.map(user => {
    const [open] = useState(false);
    return <li key={user.id}>{open ? user.bio : user.name}</li>;
  });
  return <ul>{rows}</ul>;
}
```

{/* bad */}
```jsx
import { useState } from "react";
import { useStoredState } from "./storage";

function Field({ persist }) {
  const useValue = persist ? useStoredState : useState;
  const [value] = useValue("");
  return <input value={value} readOnly />;
}
```

Not reported:

{/* good */}
```jsx
import { useState } from "react";

function Profile({ user }) {
  const [name, setName] = useState(user ? user.name : "");
  if (!user) {
    return null;
  }
  return <input value={name} onChange={event => setName(event.target.value)} />;
}
```

## When not to use it

`react-hooks/rules-of-hooks` finds most of the same mistakes and is on by default in React projects. You rarely need both.
