Menu

Cykl życia komponentu React: montowanie i aktualizacja

Każdy komponent Reacta się montuje (pojawia), aktualizuje (renderuje ponownie) i odmontowuje (zostaje usunięty). Dowiedz się, jak każda faza odpowiada useEffect, poznaj metody cyklu życia klas i ich odpowiedniki w hookach oraz fazy renderowania i zatwierdzania.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Cykl życia komponentu Reacta ma trzy fazy: montowanie (komponent pojawia się na ekranie po raz pierwszy), aktualizację (renderuje się ponownie, bo zmienił się jego stan, propsy albo kontekst) i odmontowanie (zostaje usunięty). W komponentach funkcyjnych na te fazy reagujesz przez useEffect: efekt z [] uruchamia się po zamontowaniu, efekt z zależnościami po aktualizacjach, w których się zmieniły, a funkcja zwracana przez efekt przy odmontowaniu.

Konsola pod podglądem pokazuje każdą fazę w chwili, gdy następuje.

Konsola zaczyna od render, count = 0 i mounted. Każde kliknięcie Count wypisuje renderowanie i aktualizację. Unmount wypisuje unmounted; Mount again zaczyna od nowa od count = 0, bo stan został wyrzucony razem z komponentem.

Montowanie

Komponent montuje się, gdy React pierwszy raz renderuje go w danym miejscu drzewa. React wywołuje funkcję, tworzy węzły DOM z zwróconego JSX, wstawia je, pozwala przeglądarce odmalować ekran, a potem uruchamia efekty komponentu.

useEffect(fn, []) to miejsce, w którym uruchamiasz rzeczy, które mają istnieć tak długo, jak komponent jest na ekranie: subskrypcję, timer, połączenie, pierwsze żądanie danych. Uruchamia się po odmalowaniu, więc nigdy nie opóźnia pierwszej klatki.

Aktualizacja

Komponent się aktualizuje (renderuje ponownie), gdy:

  • zmienia się jego własny stan,
  • jego rodzic renderuje się ponownie (domyślnie każde dziecko też się renderuje, bez względu na to, czy jego propsy się zmieniły),
  • zmienia się kontekst, który czyta.

Po każdej aktualizacji React uruchamia efekty, których zależności się zmieniły. Zanim ponownie uruchomi efekt, uruchamia jego poprzednią funkcję czyszczącą, więc stara subskrypcja zostaje zamknięta, zanim otworzy się nowa. Strona o renderowaniu dokładniej omawia, co wywołuje renderowanie.

Odmontowanie

Komponent się odmontowuje, gdy rodzic przestaje go renderować (jak robi to {show && <Counter />} powyżej), gdy zmienia się jego key albo gdy odmontowany zostaje sam root. React usuwa jego węzły DOM, uruchamia funkcję czyszczącą każdego efektu i wyrzuca jego stan. Jeśli komponent później znowu się pojawi, jest zupełnie nową instancją.

Rodzice i dzieci

React renderuje od góry w dół, ale efekty uruchamia od dołu w górę. Gdy rodzic i dziecko montują się razem, najpierw uruchamiają się efekty dziecka, więc efekt rodzica może polegać na tym, że jego dzieci są w pełni gotowe.

Montowanie wypisuje render Parent, render Child, Child effect, Parent effect. Naciśnij Remove, a funkcje czyszczące uruchomią się w odwrotnej kolejności: Parent cleanup, potem Child cleanup.

Fazy renderowania i zatwierdzania

Każda aktualizacja przechodzi przez dwie fazy:

  1. Faza renderowania. React wywołuje twoje komponenty, żeby wyliczyć nowy JSX, i porównuje go z poprzednim wynikiem. Na ekranie nic się jeszcze nie zmienia. React może tę pracę wstrzymać, wykonać dwa razy w StrictMode albo wyrzucić, dlatego renderowanie musi być czyste: żadnych żądań, subskrypcji ani zmian zmiennych zewnętrznych.
  2. Faza zatwierdzania (commit). React stosuje różnice w DOM, podłącza refy i uruchamia callbacki useLayoutEffect, wszystko zanim przeglądarka odmaluje ekran. Callbacki useEffect uruchamiają się po tym, zwykle gdy przeglądarka już odmalowała ekran. Gdy aktualizację spowodowało kliknięcie albo inne dyskretne zdarzenie wejściowe, React uruchamia je zamiast tego zaraz po efektach układu, żeby wynik był gotowy przed następnym zdarzeniem.

Każde kliknięcie wypisuje trzy linie w tej samej kolejności. Te efekty nie mają tablicy zależności, więc uruchamiają się po każdym renderowaniu. Dodaj [] jako drugi argument do obu, a uruchomią się tylko po pierwszym.

Metody cyklu życia klas i ich odpowiedniki w hookach

Komponenty klasowe rozpisują cykl życia na nazwane metody. Spotkasz je w starszym kodzie i w granicach błędów, które nadal wymagają klasy.

Metoda klasyKiedy się uruchamiaOdpowiednik w komponencie funkcyjnym
constructorraz, przed pierwszym renderowaniemuseState(initial), useRef
static getDerivedStateFromPropsprzed każdym renderowaniemwylicz wartość podczas renderowania albo zresetuj przez key
renderprzy każdym renderowaniuciało funkcji
componentDidMountpo tym, jak pierwsze renderowanie jest w DOMuseEffect(fn, [])
shouldComponentUpdateprzed aktualizacją, może ją pominąćReact.memo (zwraca odwrotną odpowiedź: „czy propsy są równe")
getSnapshotBeforeUpdatetuż przed zmianą DOMbrak bezpośredniego hooka; najbliżej jest useLayoutEffect z refem
componentDidUpdatepo każdej aktualizacjiuseEffect(fn, [deps]) (uruchamia się też po zamontowaniu)
componentWillUnmountprzed usunięciemfunkcja czyszcząca zwracana przez useEffect
getDerivedStateFromError, componentDidCatchgdy dziecko rzuci błądbrak: napisz klasę granicy błędów

Oto klasa, która wypisuje każdą metodę w chwili jej wykonania:

Montowanie wypisuje constructor, getDerivedStateFromProps, render, componentDidMount. Kliknięcie wypisuje getDerivedStateFromProps, shouldComponentUpdate, render, getSnapshotBeforeUpdate, componentDidUpdate. Niech shouldComponentUpdate zwraca false, a kliknięcia przestaną aktualizować przycisk: stan się zmienia, ale React pomija renderowanie. Strona o komponentach klasowych pokazuje, jak przerobić taką klasę na funkcję.

Myśl o synchronizacji, a nie o cyklu życia

Tabela hooków przydaje się do czytania starego kodu, ale może skłonić cię do pisania efektów, które kopiują nawyki z klas, na przykład jeden duży efekt „po zamontowaniu" i jeden duży efekt „po aktualizacji". Efekt lepiej czytać jako „utrzymuj tę zewnętrzną rzecz w zgodzie z tymi wartościami": połącz się z roomId, a gdy roomId się zmieni, rozłącz się i połącz ponownie. Pisz jeden efekt na każdą rzecz, którą synchronizujesz, wymień wartości, których używa, jako zależności i pozwól Reactowi zdecydować, kiedy go uruchomić.

Najczęściej zadawane pytania

Jakie są fazy cyklu życia komponentu Reacta?

Montowanie (React tworzy komponent i umieszcza jego wynik na ekranie), aktualizacja (komponent renderuje się ponownie, bo zmienił się jego stan, propsy albo kontekst) i odmontowanie (komponent zostaje usunięty i sprząta po sobie).

Jaki jest odpowiednik componentDidMount w hookach?

useEffect(() => { ... }, []). Pusta tablica zależności sprawia, że efekt uruchamia się raz, po tym, jak pierwsze renderowanie jest na ekranie. Funkcja, którą zwraca, to odpowiednik componentWillUnmount.

Jaki jest odpowiednik componentDidUpdate w hookach?

useEffect z interesującymi cię wartościami w tablicy zależności, na przykład [userId]. W odróżnieniu od componentDidUpdate uruchamia się też po pierwszym renderowaniu, więc obejmuje montowanie i aktualizację razem.

W jakiej kolejności uruchamiają się efekty rodzica i dziecka?

React renderuje od rodzica w dół, ale efekty uruchamia od dzieci w górę: efekt dziecka uruchamia się przed efektem rodzica. Przy odmontowaniu funkcja czyszcząca rodzica uruchamia się przed funkcją czyszczącą dziecka.

Co to są fazy render i commit?

W fazie renderowania React wywołuje twoje komponenty, żeby ustalić, jak ma wyglądać ekran; może tę pracę wstrzymać albo wyrzucić. W fazie zatwierdzania (commit) stosuje zmiany w DOM i uruchamia efekty układu; zwykłe efekty uruchamiają się po tym, zwykle gdy przeglądarka już odmalowała ekran.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ