useState keep the value?Not in your function; that dies every render. React keeps a hidden list per component instance. Each hook call, in order, gets the next slot. First useState → slot 0. Second → slot 1. useEffect → slot 2.
On the next render, React walks the same list in the same order and hands each call its slot back. Press render a few times. The calls change; the slots don't.
render #1
if.The slots are matched by position, nothing else. If a hook is skipped on one render, every hook after it shifts up one slot and reads the wrong value.
Put the first useState inside a condition and toggle it off. Watch open receive "Ada".
All aligned. Now flip the condition.
Once. (In next dev you'll see it twice: React's Strict Mode mounts, unmounts and remounts every component on purpose to catch effects that don't clean up. Production runs it once.) The array lists what the effect depends on. React compares it to last render's array; if nothing changed, it skips. An empty array never changes, so: first render only. No array means "no comparison", so: every render. This is the mechanical reason for the three idioms on the right.
Because the slots are matched by call order, a function that calls useState twice just takes two slots from the same list. Name it use… so the linter can check the rules inside it, and you have a custom hook.
This is how useUser(), useDebounce(), and every hook a library gives you work. They're not a special kind of thing. They're bundles of slots.
function useToggle(initial = false) { const [on, setOn] = useState(initial); // takes a slot const toggle = () => setOn(v => !v); return [on, toggle]; } function Menu() { const [open, toggle] = useToggle(); // slot 0, via the hook const [name] = useState("Ada"); // slot 1 … }
Top of the function, never in a loop or condition, only from components or other hooks. All three are the same sentence said three ways.