Learning
Všechny články
Frontend3. srpna 2026 5 min

React si hooky pamatuje podle pořadí, ne podle jména

Proč hooky visí na fiberu jako spojový seznam a kurzor se posouvá

Hook nemá jméno, má pořadí

Pravidlo hooků zní: volej je jen na nejvyšší úrovni komponenty, nikdy v podmínce, cyklu ani vnořené funkci. Většina lidí ho bere jako otravné omezení lintru. Ve skutečnosti přímo popisuje, jak jsou hooky uvnitř postavené. Když víš proč, přestane to být pravidlo k zapamatování a stane se z toho něco zřejmého.

Klíč je tohle: React nespojuje stav s tvým hookem podle názvu. Nikde si neuloží „tenhle useState je počítadlo". Spojuje ho podle pořadí, ve kterém hook zavoláš.


Spojový seznam pověšený na fiberu

Každá komponenta má svůj fiber — uzel, který drží její stav mezi rendery. Na něm visí pole memoizedState, a to je ve skutečnosti hlava spojového seznamu hooků. První hook je první uzel, druhý hook druhý uzel, a tak dál.

Při renderu si React drží kurzor, který ukazuje na aktuální uzel. Zavoláš useState — React vezme uzel, na který kurzor míří, vrátí z něj hodnotu a kurzor posune na další. Zavoláš useEffect — vezme se další uzel v řadě. Žádné jméno, žádný klíč. Jen „další v pořadí".

Při prvním renderu se seznam staví: každé volání hooku přidá jeden uzel. Při každém dalším renderu se ten samý seznam jen prochází odshora. Proto musí být volání pokaždé stejná a ve stejném pořadí — kurzor spoléhá, že n-té volání hooku vždycky sáhne na n-tý uzel.


Proč podmíněný hook rozbije všechno

Teď je jasné, co se stane, když hook schováš do podmínky:

if (isLoggedIn) {
  const [name, setName] = useState('');
}
const [count, setCount] = useState(0);

Při prvním renderu je isLoggedIn true. Seznam má dva uzly: uzel 0 pro name, uzel 1 pro count. Při dalším renderu je podmínka false. useState pro name se nezavolá, takže první volání hooku je teď to pro count — a kurzor mu podstrčí uzel 0, tedy stav, který patřil name. count najednou čte cizí data. Od té chvíle je celý seznam posunutý o jedna.

React tenhle rozjezd neumí uhádnout, protože nemá podle čeho. Jediné, co zaručuje správné napárování, je neměnné pořadí volání. Proto podmínky, cykly a předčasné return před hookem padají — všechny mění, kolik hooků se ten render zavolá.


Co si z toho odnést

Pravidlo hooků není konvence, je to důsledek datové struktury. Hooky jsou spojový seznam na fiberu a čtou se přes kurzor, který se posouvá s každým voláním. Jméno hooku v tom nehraje roli — záleží jen na tom, kolikátý v pořadí je.

Když příště zatoužíš zavolat hook v podmínce, převeď to naopak: podmínku dej dovnitř hooku. Místo if (x) useEffect(...) napiš useEffect(() => { if (x) ... }). Hook se volá vždycky, seznam zůstane stabilní a kurzor sedí. A eslint-plugin-react-hooks ti tohle pohlídá dřív, než se posunutý stav projeví za běhu.

Zdroje

Poslech místo čtení — 2 zdroje k načtení.