State w React.js 2

Ten wpis jest 9 częścią z 32 w kursie React.js

Pod koniec poprzedniego wpisu zadałem podchwytliwe ćwiczenie dotyczące state w React.js. Jeśli jeszcze go nie wykonałaś/eś to teraz jest ten moment, aby wrócić i spróbować 😉 W tym wpisie rozwijam temat state, opisuję dokładniej jak działa setState i jakie argumenty przyjmuje.

Zacznijmy może od wykonania ćwiczenia z poprzedniego wpisu. Zadanie brzmiało tak:

Dodaj dwa nowe liczniki. Pierwszy, który będzie zliczał wszystkie kliknięcia w przyciski (tzn. kliknięcie w + i - daje 0 na obecnym liczniku oraz 2 na nowym liczniku), oraz drugi, który będzie zliczał podwójne kliknięcia (tzw. double click) na elemencie z wynikiem.

Wydaje się proste, ale implementacja odkrywa przez Tobą pewien ważny szczegół dotyczący działania funkcji setState. W jaki sposób chcielibyśmy tutaj aktualizować stan? Musimy przechowywać jeden licznik z sumą, drugi zliczający łączne kliknięcia oraz trzeci, który będzie przechowywał podwójne kliknięcia. To co jest tutaj istotne to fakt, że w momencie pojedynczego kliknięcia aktualizujesz tylko dwa liczniki, a trzeci pozostaje bez zmian. Jak to najprościej zaimplementować?

Jak działa setState?

increment() {
    this.setState({
      sumCount: this.state.counter + 1
      totalCount: this.state.totalCount + 1
      doubleClickCount: this.state.dblClickCount
    })
  }

Działa, po prostu do doubleClickCount zawsze przypisana zostaje niezmieniona wartość this.state.doubleClickCount. Ale czy to konieczne? Co by było, gdyby stan komponentu składał się nie z 3, a z 15 pól? Nie dyskutujmy teraz czy to dobre rozwiązanie, tylko zastanów się jak by musiała wyglądać każda aktualizacja stanu… właśnie.

Na szczęście setState jest mądrzejsze i automatycznie łączy obecny stan z tym podanym mu jako argument — i nadpisuje tylko podane własności. To co się nie zmienia pomijasz:

increment() {
    this.setState({ // doubleClickCount pozostanie niezmienne
      sumCount: this.state.counter + 1
      totalCount: this.state.totalCount + 1
    })
  }

A tutaj w pełni działające rozwiązanie:

See the Pen Stan komponentów React.js by Michał Miszczyszyn (@mmiszy) on CodePen.

Funkcja przekazana do setState

Widzisz, że do setState możemy po prostu przekazać obiekt, który zostanie połączony z obecnym stanem i nadpisze podane własności. I to, do niedawna, była jedyna opcja. Od Reacta 16 polecanym sposobem aktualizowania stanu jest przekazanie do setState funkcji, a nie obiektu. Taka funkcja to tzw. updater. Jak to działa? Updater to taka funkcja, która jako argument przyjmuje obecny stan i jako wynik zwraca obiekt, który zostanie połączony z istniejącym stanem. Przykładowo dla nas:

  increment() {
    this.setState(prevState => {
      return {
        sumCount: prevState.sumCount + 1,
        totalCount: prevState.totalCount + 1
      };
    });
  }

Jakie są zalety tego rozwiązania względem po prostu przekazania obiektu do setState? W tym przypadku żadne. setState jest asynchroniczne (o tym zaraz) i sprawia problemy, gdy wywołamy je kilka razy pod rząd — tutaj pomoże nam updater. Dodatkowo, updater pomaga poprawić wydajność aplikacji — jeśli w updaterze zwrócisz null to nie zostanie wykonany ponowny render. Poświęcę temu wszystkiemu inny wpis!

setState i callback

Dokładnie tak jak w nagłówku. Co to oznacza? Najprościej mówiąc, że wywołanie setState nie zmienia stanu od razu, tylko dopiero po jakimś czasie. Czyli, przykładowo, próba odczytania stanu od razu po jego zmianie przez setState pokaże nam nadal stary, nieaktualny stan. Otwórz konsolę i kliknij w przycisk w tym przykładzie:

See the Pen setState i odczyt state by Michał Miszczyszyn (@mmiszy) on CodePen.

Jak naprawić ten problem? Otóż setState przyjmuje też drugi argument: callback. Jeśli jako drugi argument przekażesz funkcję to zostanie ona wywołana w momencie, gdy stan będzie już zaktualizowany. Spójrz po prostu na przykład (z widoczną konsolą):

See the Pen Callback do setState by Michał Miszczyszyn (@mmiszy) on CodePen.

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

Ćwiczenie

Ćwiczenie: Napisz komponent, który będzie miał dwa inputy na imię i nazwisko. Obok, powinien się wyświetlać tekst wpisany w te pola (imię nazwisko). Użyj do tego atrybutu onInput oraz funkcji setState.

Napisz w komentarzu jak Ci się podoba obsługa formularzy w React. Poświęcę temu jeden z kolejnych odcinków, więc chcę wiedzieć już teraz jakie masz uwagi 🙂