Join the discussion
Comments
Loading comments...
Cookie preferences
We use essential cookies for sign-in and preferences. With your permission, we also use basic analytics to improve lessons.
Join the discussion
Loading comments...
We use essential cookies for sign-in and preferences. With your permission, we also use basic analytics to improve lessons.
Voyez comment React gère les hooks en liste chaînée, traite les mises à jour d'état et re-rend.
Les hooks sont stockés sous forme de liste chaînée simple sur le nœud Fiber. Lorsque votre composant s'affiche, React parcourt cette liste dans l'ordre — associant chaque appel de hook (useState, useEffect, useRef, etc.) à son state stocké. C'est pourquoi les Règles des Hooks existent : si vous appelez des hooks conditionnellement, l'ordre de la liste change et React lit le mauvais state pour le mauvais hook.
Chaque appel de hook (useState, useEffect, useRef, useMemo…) crée un objet 'Hook' avec un champ memoizedState et un pointeur next. React ajoute chacun à la liste dans l'ordre d'appel. La liste est stockée dans le champ memoizedState du nœud Fiber.
Un objet hook useState stocke : memoizedState (valeur courante), queue (liste chaînée d'appels setState en attente) et dispatch (la fonction setState que vous utilisez dans votre composant). La fonction dispatch est stable — elle ne change jamais entre les rendus.
Lorsque vous appelez setState(newValue), React ne met pas immédiatement à jour le state. Au lieu de cela, il ajoute un objet Update à la file d'attente du hook et planifie un re-rendu du fiber. Plusieurs appels setState dans un même gestionnaire d'événement sont regroupés en un seul re-rendu.
Au prochain rendu, React parcourt à nouveau la liste des hooks. Pour chaque hook useState, il traite toutes les mises à jour en file d'attente en les exécutant dans l'ordre (ou en appelant la fonction reducer pour useReducer). La valeur calculée finale devient le nouveau memoizedState.
Un objet hook d'effet stocke : create (le callback que vous avez passé), destroy (la fonction de nettoyage retournée la dernière fois), deps (le tableau de dépendances) et un tag indiquant s'il s'agit d'un useEffect, useLayoutEffect ou useInsertionEffect.
Les hooks sont stockés sous forme de liste chaînée simple sur le nœud Fiber. Ordre d'appel = ordre de la liste. Les hooks conditionnels brisent la liste.
Le champ d'un objet Hook qui stocke sa valeur courante. Pour useState : la valeur du state. Pour useRef : '{' current: valeur '}'. Pour useMemo : le résultat mis en cache.
Une liste chaînée circulaire d'appels setState en attente de traitement au prochain rendu. Plusieurs mises à jour sont regroupées en un seul vidage de file.
React permute l'implémentation des hooks selon la phase de rendu. Lors du premier rendu : HooksDispatcherOnMount. Lors des re-rendus : HooksDispatcherOnUpdate. C'est pourquoi les hooks ne peuvent pas être appelés en dehors des composants.
Appelez les hooks uniquement au niveau supérieur (jamais dans des conditionnels/boucles) et uniquement depuis des fonctions React. Ces règles existent parce que React identifie les hooks par leur position dans la liste chaînée.
1// Your component:2function Counter() {3 const [count, setCount] = useState(0); // Hook 14 const [name, setName] = useState('Bob'); // Hook 25 const ref = useRef(null); // Hook 367 useEffect(() => { ... }, [count]); // Hook 48}910// React's internal hooks linked list for this fiber:11Hook1 { memoizedState: 0, next: Hook2 } // count12Hook2 { memoizedState: 'Bob', next: Hook3 } // name13Hook3 { memoizedState: { current: null }, next: Hook4 } // ref14Hook4 { memoizedState: { create, destroy, deps: [0] }, next: null }1516// If you conditionally call hook 2:17// Hook1 → Hook3 → Hook4 (Hook2 slot is now useRef!)18// React reads "Bob" as the ref's current value → BUG
Comprendre les internals des hooks explique pourquoi les Règles des Hooks ne sont pas des restrictions arbitraires mais des nécessités techniques. Cela explique aussi pourquoi la fonction setter useState est toujours stable (elle est attachée à la file, pas à la valeur), pourquoi les hooks fonctionnent entre les rendus (ils sont persistés sur le fiber) et pourquoi vous pouvez créer des hooks personnalisés — ce sont simplement des fonctions qui appellent d'autres hooks, ajoutant plus de nœuds à la liste.
You add an early return in a component for a loading state: `if (loading) return <Spinner />`. After the data loads, React crashes with 'Rendered more hooks than during the previous render.'
The early return is ABOVE some hook calls. On the first render (loading=true), React processes 2 hooks. On the second render (loading=false), it processes 5 hooks. React's linked list has 2 slots but encounters 5 hook calls — the list is corrupted.
Move ALL hook calls above any conditional returns. The early return must come AFTER the last hook call. React hooks are a linked list indexed by call order — the call count must be identical across every render of the same component.
Takeaway: The 'Rules of Hooks' aren't arbitrary restrictions — they're a direct consequence of the linked list data structure. React identifies hooks by position (call order), not by name. Changing the number of hooks between renders corrupts the list.
You build a custom `useToggle` hook used in 3 different components. You notice that toggling in one component doesn't affect the others — but you're confused about WHY, since they share the same hook code.
Developers sometimes assume custom hooks share state like a global singleton. They expect `useToggle()` in Component A and Component B to share the same boolean value, leading to incorrect architecture decisions.
Each component has its own fiber node with its own hooks linked list. When Component A calls `useToggle()`, React creates a hook node in Component A's list. Component B gets a completely separate hook node in its own list. Custom hooks are just a code-sharing mechanism — state is always local to the calling component's fiber.
Takeaway: Custom hooks share LOGIC, not STATE. Each component instance gets its own copy of the hook's state because each fiber maintains its own hooks linked list. To share state between components, you need Context, a state manager, or lifting state up.