Hook useState w Reaccie służy do przechowywania wartości stanu komponentu i aktualizowania interfejsu użytkownika za pomocą ponownego renderowania po zmianie stanu.
useState powoduje ponowne renderowanie całego komponentu, ale wykorzystuje wirtualny DOM (Virtual DOM), aby zminimalizować rzeczywiste zmiany w DOM.
Wewnętrzna implementacja useState opiera się na liście połączonej (linked list), która łączy aktualnie renderowany komponent z hookiem, utrzymując wartość stanu i wywołując różne funkcje w zależności od zdarzeń aktualizacji.
Dziwnym trafem w środowisku React bardzo lubią rzeczy z przedrostkiem use
useServer, useCallback, useState, useMemo itd.
Własne hooki również mają przedrostek use
Skąd się to wzięło?
useState to popularny hook.
Przechowuje wartość stanu i powoduje ponowne renderowanie, gdy się ona zmienia. Jest naprawdę prosty.
To przykład znany wszystkim.
Skoro mówimy, że ponowne renderowanie następuje po zmianie wartości stanu, to jaki jest zakres tego renderowania?
Tylko tag p? A może tag button również?
Odpowiedź brzmi: cały komponent, w którym wywołano useState.
Chociaż renderowany jest ExampleComponent,
to wykorzystuje się wirtualny DOM do porównywania wartości i modyfikowania tylko tych części DOM, które uległy zmianie.
useState jest wywoływany przy każdym renderowaniu, jak więc wartość stanu jest zachowywana?
Odpowiedź na to pytanie tkwi w strukturze useState.
Powyższy kod to rzeczywisty kod useState w React.
Pobiera dispatchera z obiektu globalnego i wywołuje useState.
Na podstawie tego fragmentu kodu trudno zrozumieć strukturę.
Zagłębiając się dalej, napotykamy następujący kod:
Pobiera hooka i przypisuje funkcję set bezpośrednio do kolejki (queue) w hooku za pomocą bind.
(bind wiąże this z istniejącą funkcją, a pozostałe argumenty są używane jako argumenty funkcji. Zwraca nową funkcję z powiązanym this).
Na podstawie tego fragmentu kodu nadal trudno zrozumieć powód zachowania.
Zbadajmy to dalej.
Możemy zauważyć, że wartość początkowa jest przypisywana za każdym razem. To nie wyjaśnia, jak stan jest zachowywany.
Zbadajmy to dalej. Hook wygląda podejrzanie.
currentlyRenderingFiber i workInProgressHook to zmienne globalne.
Wykorzystując przypisanie od prawej do lewej, zaimplementowano listę połączoną.
Dlatego też, po rozwinięciu hooka, oczekujemy następującej struktury:
Na początku dodawane są kolejne wartości.
Nadal nie jest to jasne, więc po przejrzeniu innych implementacji useState
okazało się, że nie zawsze wywoływana jest funkcja mountState, a w przypadku ponownego renderowania – updateState i rerenderState.
Dlatego struktura jest taka, jak pokazano powyżej, a w zależności od zdarzenia wywoływane są różne funkcje.
Jeśli chcesz zobaczyć kod na własne oczy, zajrzyj do pliku react/packages/react-reconciler/src/ReactFiberHooks.js.