React Hooks — wprowadzenie i motywacja

Ten wpis jest 33 częścią z 39 w kursie React.js
wp-content/uploads/2017/10/React_logo_wordmark-300x101-1-e1508612391308.png
  1. React.js: Wprowadzenie do kursu 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: globalny store i jednokierunkowy przepływ danych
  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

Jakiś czas temu zrobiło się głośno na temat React Hooks. Co to jest i po co Ci to? Przez dłuższy czas celowo nie pisałem o tym na blogu, gdyż była to ledwie propozycja i to do tego mocno niestabilna. Teraz jednak sytuacja się zmieniła i wszystko wskazuje na to, że React Hooks wkrótce trafią do wersji stabilnej. Czas się zaprzyjaźnić! Dlatego powstał kurs React Hooks.

Stan w komponentach funkcyjnych

Bolączką komponentów funkcyjnych było to, że były one bezstanowe. Tzn. działały idealnie do renderowania treści na podstawie propsów, jednak same nie mogły zawierać state. Aby dodać stan, trzeba było taki komponent zrefaktorować na klasę — z tego powodu wiele osób zalecało po prostu zawsze używać klas i ignorować komponenty funkcyjne zupełnie. Hooki całkowicie zmieniają tę sytuację.

Motywacja dla powstania React Hooks

Jednak dodanie alternatywnej składni to tak naprawdę nie jest motywacja twórców Reacta. Po co alternatywna składnia, skoro miałaby ona niczego de facto nie zmieniać? Są lepsze powody dla istnienia Hooków.

Tworzenie uniwersalnej logiki zawierającej stan

Tworzenie takiej logiki, którą można by ponownie wykorzystać w różnych komponentach, a która zawiera także stan. To właśnie do rozwiązania tego problemu powstały takie wzorce jak Higher Order Components czy Render Props. Te jednak przyniosły kolejne kłopoty… Hooki zdają się wszystko rozwiązywać i upraszczać.

Uproszczenie kodu komponentów stanowych dzięki React Hooks

Przyjrzyjmy się typowemu komponentowi stanowemu. Warto pamiętać, kiedy używać stanu lokalnego w React. Żeby było ciekawiej, komponent ten podpina się pod subskrypcję danych (np. observable — temat mi bliski bo stworzyłem bibliotekę react-with-observable). Przy odmontowywaniu musi tę subskrypcję oczywiście usunąć, a w przypadku zmian pamiętać o aktualizacji

class MyComponent extends React.Component {
  componentDidMount() {
    this.subscribe();
  }

  componentWillUnmount() {
    this.unsubscribe();
  }

  subscribe() {
    this._unsubscribe = this.props.observable.subscribe(…);
  }

  unsubscribe() {
    if (this._unsubscribe) {
      this._unsubscribe();
    }
  }

  componentDidUpdate(prevProps) {
    if (prevProps.observable !== this.props.observable) {
      this.unsubscribe();
      this.subscribe();
    }
  }

  render() {
    // …
  }
}

(kod wzorowany na tweecie @jamiebuilds)

WOAH, to całkiem sporo kodu jak na prostą subskrypcję, mam rację? I tyle rzeczy, o których trzeba pamiętać… A do tego nie ma żadnego sposobu, aby z tej logiki móc skorzystać ponownie w innym komponencie!

Powiązana logika jest… porozrzucana

Często, szczególnie w bardziej rozbudowanych komponentach, logika związana z tą samą rzeczą jest porozrzucana po różnych metodach cyklu życia. Jest to widoczne już w powyższym przykładzie, a ta klasa jeszcze tak naprawdę nic nie robi!

Statyczna analiza i minifikacja kodu

Okazuje się, że JS-owe klasy nie są czymś co można łatwo minifikować albo analizować statycznie. Każda tworzona metoda może być zarówno publiczna, jak i prywatna — nie ma sposobu, by to wiedzieć! Z tego powodu niemożliwa jest minifikacja nazw metod — nie wiadomo przecież czy danej funkcji ktoś/coś nie wywołuje też z zewnątrz klasy.

Dodajmy do tego problemy z nierozumieniem działania this w JS przez wiele osób i wynikającą z tego konieczność bindowania metod, albo używania eksperymentalnej składni i pamiętania o wykorzystywaniu funkcji strzałkowych i jakiegoś transpilatora typu Babel… Ałć!

Problemy, które rozwiązują React Hooks

Jak powyższe problemy rozwiązują React Hooks?

  • Fragmenty logiki zawierającej stan są zamykane w funkcjach, z których można korzystać w wielu komponentach.
  • Same komponenty stają się funkcjami, co mocno upraszcza pracę z nimi.
  • Kod wewnątrz funkcji jest łatwy do optymalnej minifikacji.
  • Powiązana logika jest blisko siebie, a nie porozrzucana.

Brzmi dobrze? Do tego bez wątpienia Hooki są łatwiejsze i bardziej przystępne dla początkujących. Czyżby to strzał w 10? Moim zdaniem tak i dlatego napisałem ten kurs React Hooks!

Porównanie kodu z Hookami i bez nich

Spójrz na klasę z początku wpisu. Niemal dokładnie ten sam kod z użyciem React Hooks jest nie tylko krótki, ale też prosty:

function MyComponent(props) {
  useEffect(() => {
    return props.observable.subscribe(…);
  }, [props.observable]);

  // …
}

Rzuć też okiem na inne porównania. Kilka subskrypcji w jednym komponencie:

Minifikacja:

(źródło: twitter.com/jamiebuilds/status/1055988893303037952)

I wreszcie, związane ze sobą fragmenty kodu porozrzucane w klasie i uporządkowane blisko siebie w funkcji z Hookami:

Czy to Cię przekonuje? Mnie absolutnie tak.

Jeśli chcesz na bieżąco dowiadywać się o kolejnych częściach kursu React.js Hooks to koniecznie śledź mnie na Facebooku i zapisz się na newsletter.

Chcę nauczyć się Hooków!

Świetnie! Szczęśliwie się składa, że właśnie pracuję nad kolejną częścią kursu React Hooks 😉 Jeśli jednak bardzo Ci się spieszy to zajrzyj tutaj: Poznaj React w dwa dni na szkoleniu z Type of Web!

Nawigacja po kursie:
  1. React.js: Wprowadzenie do kursu 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: globalny store i jednokierunkowy przepływ danych
  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