Metody cyklu życia komponentu w React.js

Ten wpis jest 10 częścią z 39 w kursie React.js
wp-content/uploads/2017/10/React_logo_wordmark-300x101-1-e1508612391308.png
  1. Wprowadzenie do kursu React.js od podstaw
  2. Poznaj React.js
  3. Pierwszy komponent w React.js
  4. Props czyli atrybuty w React.js
  5. Podział na komponenty w React.js
  6. Klasy jako komponenty React.js
  7. Interakcja z komponentami React.js
  8. Stan komponentów React.js
  9. State w React.js 2
  10. Metody cyklu życia komponentu w React.js
  11. React.js w przykładach: filtrowanie statycznej listy
  12. Tworzenie aplikacji React.js dzięki create-react-app
  13. React.js na GitHub Pages dzięki create-react-app
  14. Testowanie aplikacji React.js — podstawy Enzyme
  15. Testowanie React.js w Enzyme — props, state i interakcje
  16. Poprawne bindowanie funkcji w React.js
  17. Odpowiadam na pytania: Babel, ECMAScript, destrukturyzacja, onClick, className
  18. Komunikacja pomiędzy komponentami w React.js
  19. Komunikacja z API w React.js
  20. Formularze w React.js — kontrolowane komponenty
  21. Formularze w React.js — niekontrolowane komponenty
  22. Odpowiadam na pytania: props, nawiasy klamrowe, funkcje vs klasy, import react
  23. TDD w React.js z pomocą react-testing-library
  24. Flux i Redux
  25. React + Redux — kurs: wprowadzenie i podstawy
  26. React + Redux — filtrowanie listy, proste selektory
  27. Projektowanie komponentów: Presentational & Container Components
  28. Asynchroniczność w Redux: redux-thunk
  29. Kiedy używać state, a kiedy Redux?
  30. Nowe metody cyklu życia: getDerivedStateFromProps i getSnapshotBeforeUpdate
  31. Leniwe ładowanie komponentów w React dzięki import
  32. Higher Order Reducers — Redux i powtarzanie kodu
  33. React Hooks — wprowadzenie i motywacja
  34. React Hooks: useState, czyli stan w komponentach funkcyjnych
  35. React Hooks: useState — wiele stanów, callbacki i inne niuanse
  36. React Hooks: useEffect — efekty uboczne w komponencie
  37. React Hooks a żądania do API
  38. useReducer — przenoszenie logiki poza komponent
  39. useMemo, useCallback, czyli rozwiązanie problemów ze zmieniającymi się propsami

Przy okazji omawiania komponentów będących klasami w React.js, wspomniałem też o możliwości korzystania z metod cyklu życia (lifecycle methods). Chciałbym do tego tematu teraz powrócić. Pokażę jakie metody cyklu życia definiuje React.js, do czego one służą i kiedy mogą się przydać.

Cykl życia komponentu

Bardzo dokładnie omawiamy cykl życia komponentów na szkoleniach. Poznaj React w dwa dni na naszym szkoleniu!

Każdy komponent ma pewien określony cykl życia. Na odpowiednich etapach wywoływane są też jego metody cyklu życia. Możemy je podzielić ogólnie na dwie grupy:

  • z nazwami zaczynającymi się od will — wywoływane zanim się coś wydarzy
  • z nazwami zaczynającymi się od did — wywoływane po tym jak coś się zdarzyło

Oto kolejne etapy życia komponentów:

Montowanie

Komponent jest tworzony i dodawany do drzewa Dom.

  • constructor(props) — jeśli definiujesz konstruktor to nie zapomnij wywołać w nim super(props) na samym początku; możesz też tam ustawić this.state = {…} bez konieczności używania setState. To będzie początkowy stan aplikacji. Inne operacje (efekty uboczne, subskrypcje) powinny się znaleźć w componentDidMount
  • componentWillMount() — wywoływany tuż przed zamontowaniem komponentu; ta metoda raczej Ci się nie przyda
  • render() — funkcja, która powinna zwrócić jeden z możliwych wyników:
    • element (JSX)
    • tablicę elementów (JSX)
    • string lub liczbę
    • null (nic się nie renderuje)
    • boolean (nic się nie renderuje)
    • Portal (stworzony przez ReactDOM.createPortal(…))
  • componentDidMount() — wywoływana po zamontowaniu komponentu; to dobre miejsce na jakiekolwiek funkcje polegające na DOM lub na subskrypcje (nie zapomnij o usunięciu subskrypcji w componentWillUnmount()!)

Aktualizacja

Update może zostać wywołany gdy zmieniają się props lub state.

  • componentWillReceiveProps(nextProps) — wywoływana m.in. gdy zmieniają się propsy (np. gdy element-rodzic je zmienia); warto porównać this.props z nextProps i sprawdzić czy rzeczywiście coś się zmieniło (bo nie zawsze musi…)
  • shouldComponentUpdate(nextProps, nextState) — wywoływana zawsze przed render(); jeśli z tej funkcji zwrócisz false to render() nie zostanie wykonany, a widok się raczej nie przerenderuje — można to wykorzystać do optymalizowania aplikacji; UWAGA: komponenty-dzieci nadal mogą się przerenderować np. gdy zmieni się ich state, a w przyszłości React będzie traktował funkcję  shouldComponentUpdate() tylko jako wskazówkę, a nie wyznacznik — wrócę do tego tematu jeszcze
  • componentWillUpdate(nextProps, nextState) — wywoływana tuż przed render() — pamiętaj aby nie modyfikować state wewnątrz tej funkcji
  • render() — j.w.
  • componentDidUpdate(prevProps, prevState) — wywoływana od razu po renderze; dobre miejsce na zmiany w DOM (jeśli takowe są potrzebne)

Odmontowanie

Wywoływane gdy komponent jest usuwany z DOM

  • componentWillUnmount() — wywoływana przed usunięciem komponentu z DOM; dobre miejsce na „posprzątanie” po sobie — usunięcie timerów, subskrypcji, zmian w DOM itd.

Łapanie błędów

  • componentDidCatch(error, info) — wywoływana gdy pojawi się błąd w czasie renderowania, wywoływania metod cyklu życia lub w konstruktorze — zagnieżdżonych komponentów; błędy w samym komponencie nie są tutaj łapane (zostaną złapane w komponencie-rodzicu)

Przykład

Oto prosta aplikacja, która pokazuje ważny przykład używania metod cyklu życia. Są to dwa komponenty, App odpowiada za pokazywanie i ukrywanie (po kliknięciu w przycisk) drugiego komponentu. Drugi komponent to Date, który co sekundę aktualizuje stan i wyświetla aktualną datę i godzinę. Wykorzystane zostały takie lifecycle methods:

  • constructor() — ustawianie początkowego stanu
  • componentDidMount() — rozpoczęcie odliczania (setInterval)
  • componentWillUnmount() — usunięcie odliczania (clearInterval)

Warto też zwrócić uwagę na sposób w jaki komponent App renderuje komponent Date w zależności od this.state.dateVisible:

<div>
  {this.state.dateVisible && <DateComponent />}
</div>

See the Pen Metody cyklu życia komponentu w React.js by Michał Miszczyszyn (@mmiszy) on CodePen.

Jeśli chcesz na bieżąco śledzić kolejne części kursu React.js to koniecznie polub mnie na Facebooku i zapisz się na newsletter.

Ćwiczenie

Ćwiczenie: Stwórz dwa komponenty (rodzic i dziecko). Oto wymagania:

  1. Rodzic pozwala na ustawienie (input + button + onClick+ setState) jakiejś wartości liczbowej i przekazuje ją do dziecka jako props.
  2. Dziecko ma początkowo wyświetlać liczbę podaną od rodzica, a dodatkowo ma umożliwiać zwiększanie i zmniejszanie tej liczby (button + onClick + setState).
  3. W momencie gdy rodzic ustawi liczbę, dziecko powinno zresetować swój stan do podanej liczby (componentWillReceiveProps).

Aktualizacja 11.02.2019 r.: Przekreśliłem zadania powyżej. Miały one wyłącznie charakter dydaktyczny w celu poznania metody cyklu życia componentWillReceiveProps, ale wiele osób bardzo je sobie zapamiętało i stosowało podobny wzorzec w swoich aplikacjach. Poza tym React oznaczył tę metodę jako przestarzałą i niezalecaną. Zajrzyj do tego wpisu:

Nowe metody cyklu życia: getDerivedStateFromProps i getSnapshotBeforeUpdate

Sugerowane tutaj przeze mnie rozwiązanie było błędne. Prawidłowym rozwiązaniem problemu powyżej jest przeniesienie stanu dziecka wyżej — do rodzica (tzw. lifting state up). W ten sposób rodzic kontroluje stan obu inputów, a dziecko informuje go o zmianach, które chce wprowadzić. Dzięki temu unika się kilku częstych problemów: z rerenderem (który mógłby prowadzić do skasowania się wartości z inputów), z koniecznością wykrywania zmian (przez niezalecany componentWillReceiveProps), czy choćby z niejasnym przepływem danych (dane do dziecka od rodzica spływają w dół, ale tylko czasem… a dziecko nigdy nie informuje rodzica o zmianach — to niedobrze!). Oto zaktualizowana treść ćwiczenia:

Zaktualizowane ćwiczenie

Ćwiczenie: Stwórz dwa komponenty (rodzic i dziecko). Oto wymagania:

  1. Rodzic pozwala na ustawienie w inpucie jakiejś wartości liczbowej i przekazuje ją do dziecka.
  2. Dziecko ma początkowo wyświetlać liczbę podaną od rodzica, a dodatkowo ma umożliwiać zwiększanie i zmniejszanie tej liczby.
  3. W momencie, gdy rodzic ustawi liczbę, dziecko powinno zresetować swój stan do podanej liczby.
  4. Podpowiedź: Zastosuj tutaj lifting state up i stan obu komponentów trzymaj w rodzicu.

Napisz w komentarzu czy się udało. A jeśli masz jakieś wątpliwości albo nawet nie wiesz jak zacząć — odezwij się! Pomogę!

Nawigacja po kursie:
  1. Wprowadzenie do kursu React.js od podstaw
  2. Poznaj React.js
  3. Pierwszy komponent w React.js
  4. Props czyli atrybuty w React.js
  5. Podział na komponenty w React.js
  6. Klasy jako komponenty React.js
  7. Interakcja z komponentami React.js
  8. Stan komponentów React.js
  9. State w React.js 2
  10. Metody cyklu życia komponentu w React.js
  11. React.js w przykładach: filtrowanie statycznej listy
  12. Tworzenie aplikacji React.js dzięki create-react-app
  13. React.js na GitHub Pages dzięki create-react-app
  14. Testowanie aplikacji React.js — podstawy Enzyme
  15. Testowanie React.js w Enzyme — props, state i interakcje
  16. Poprawne bindowanie funkcji w React.js
  17. Odpowiadam na pytania: Babel, ECMAScript, destrukturyzacja, onClick, className
  18. Komunikacja pomiędzy komponentami w React.js
  19. Komunikacja z API w React.js
  20. Formularze w React.js — kontrolowane komponenty
  21. Formularze w React.js — niekontrolowane komponenty
  22. Odpowiadam na pytania: props, nawiasy klamrowe, funkcje vs klasy, import react
  23. TDD w React.js z pomocą react-testing-library
  24. Flux i Redux
  25. React + Redux — kurs: wprowadzenie i podstawy
  26. React + Redux — filtrowanie listy, proste selektory
  27. Projektowanie komponentów: Presentational & Container Components
  28. Asynchroniczność w Redux: redux-thunk
  29. Kiedy używać state, a kiedy Redux?
  30. Nowe metody cyklu życia: getDerivedStateFromProps i getSnapshotBeforeUpdate
  31. Leniwe ładowanie komponentów w React dzięki import
  32. Higher Order Reducers — Redux i powtarzanie kodu
  33. React Hooks — wprowadzenie i motywacja
  34. React Hooks: useState, czyli stan w komponentach funkcyjnych
  35. React Hooks: useState — wiele stanów, callbacki i inne niuanse
  36. React Hooks: useEffect — efekty uboczne w komponencie
  37. React Hooks a żądania do API
  38. useReducer — przenoszenie logiki poza komponent
  39. useMemo, useCallback, czyli rozwiązanie problemów ze zmieniającymi się propsami