- React.js: Wprowadzenie do kursu od podstaw
- Poznaj React.js
- Pierwszy komponent w React.js
- Props czyli atrybuty w React.js
- Podział na komponenty w React.js
- Klasy jako komponenty React.js
- Interakcja z komponentami React.js
- Stan komponentów React.js
- State w React.js 2
- Metody cyklu życia komponentu w React.js
- React.js w przykładach: filtrowanie statycznej listy
- Tworzenie aplikacji React.js dzięki create-react-app
- React.js na GitHub Pages dzięki create-react-app
- Testowanie aplikacji React.js — podstawy Enzyme
- Testowanie React.js w Enzyme — props, state i interakcje
- Poprawne bindowanie funkcji w React.js
- Odpowiadam na pytania: Babel, ECMAScript, destrukturyzacja, onClick, className
- Komunikacja pomiędzy komponentami w React.js
- Komunikacja z API w React.js
- Formularze w React.js — kontrolowane komponenty
- Formularze w React.js — niekontrolowane komponenty
- Odpowiadam na pytania: props, nawiasy klamrowe, funkcje vs klasy, import react
- TDD w React.js z pomocą react-testing-library
- Flux i Redux: globalny store i jednokierunkowy przepływ danych
- React + Redux — kurs: wprowadzenie i podstawy
- React + Redux — filtrowanie listy, proste selektory
- Projektowanie komponentów: Presentational & Container Components
- Asynchroniczność w Redux: redux-thunk
- Kiedy używać state, a kiedy Redux?
- Nowe metody cyklu życia: getDerivedStateFromProps i getSnapshotBeforeUpdate
- Leniwe ładowanie komponentów w React dzięki import
- Higher Order Reducers — Redux i powtarzanie kodu
- React Hooks — wprowadzenie i motywacja
- React Hooks: useState, czyli stan w komponentach funkcyjnych
- React Hooks: useState — wiele stanów, callbacki i inne niuanse
- React Hooks: useEffect — efekty uboczne w komponencie
- React Hooks a żądania do API
- useReducer — przenoszenie logiki poza komponent
- useMemo, useCallback, czyli rozwiązanie problemów ze zmieniającymi się propsami
- Wady React Hooks
- React Hooks: Piszemy własne hooki!
W poprzednim wpisie omówiłem wstępnie React Hook useState. Pod postem na blogu oraz na Facebooku pojawiło się wiele komentarzy z pytaniami. Chciałbym odpowiedzieć na nie i wyjaśnić kilka niuansów tutaj. Jak to jest z rozbudowanym stanem? Czy można wywoływać useState
w jednym komponencie wiele razy? I jak budować stan w oparciu o istniejący? To wszystko w tym wpisie.
setState przyjmuje funkcję lub stan
W poprzednim przykładzie pokazywałem tylko najprostsze wywołanie useState
i funkcji zmieniającej stan:
function App() {
const [counter, setCounter] = React.useState(0);
return (
<div>
{counter}
<button onClick={() => setCounter(counter + 1)}>+</button>
</div>
);
};
Sporo kodu, ale skup się na tym fragmencie: setCounter(counter + 1)
. Ustawiam tutaj nowy stan używając poprzedniego stanu. Mogę też jednak zrobić to nieco inaczej i przekazać do setCounter
funkcję:
setCounter(counter => counter + 1);
W ten sposób sprawiłem, że sama zmiana stanu stała się całkowicie niezależna od stałych (i zmiennych) znajdujących się w danym zasięgu. Dodatkowo daje to tę przewagę, że taką funkcję można łatwiej przenieść poza komponent!
useState nadpisuje stan
W odróżnieniu od this.setState(…)
w klasach, useState
nadpisuje cały stan podaną wartością. Dla przypomnienia: this.setState(…)
łączy podaną wartość z istniejącym stanem. Jest to zupełnie inne zachowanie i trzeba na nie zwrócić uwagę:
// wewnątrz klasy
state = { a: 1 };
// …
this.setState({ b: 2 });
// `this.state` teraz to { a: 1, b : 2 }
Porównaj to z zachowaniem useState
:
function MyComponent() {
const [state, setState] = React.useState({ a: 1 });
// …
setState({ b: 2 });
// `state` teraz to { b: 2 }
}
Można by się pokusić o użycie formy funkcyjnej setState
i ręczne połączenie starych wartości z nowymi:
setState(state => ({ ...state, b: 2 }));
// `state` to teraz { a: 1, b: 2 }
Ale nie zalecam takiego rozwiązania. Zamiast tego…
useState
można wywołać wiele razy
W klasycznym podejściu, w klasach, this.state
przechowywało cały stan danego komponentu. W przypadku Hooków można to zrobić inaczej! useState
możesz wywołać wiele razy:
function MyComponent() {
const [counter, setCounter] = React.useState(0);
const [position, setPosition] = React.useState('top');
// …
}
W ten sposób w jednym „stanie” trzymam tylko rzeczy dotyczące jednego konceptu. Nie muszę mieszać wszystkiego ze sobą w wielkim this.state
. Ponadto, ogromną zaletą tego rozwiązania jest to, że takie kawałki stanu mogę sobie łatwo wydzielić do własnych Hooków. Jak to zrobić? O tym w jednym z kolejnych wpisów.
Alternatywą dla przechowywania rozbudowanego stanu jest też Hook useReducer
. O nim również nieco później.
Stan początkowy może być funkcją
React.useState(…)
jako argument przyjmuje stan początkowy. Możesz też podać tam funkcję, aby uzyskać specjalne zachowanie. Taka funkcja będzie wywołana tylko raz, przy zamontowaniu komponentu, a jako stan początkowy zostanie ustawiona zwrócona przez nią wartość.
function MyComponent(props) {
const [state, setState] = React.useState(() => {
return calculations(props);
});
}
W jakim przypadku ma sens tak skomplikowany zapis? Wtedy, gdy funkcja calculations
jest skomplikowana, a jej wywołanie może zająć chwilę. W takim wypadku nie ma sensu wywoływać jej przy każdym renderze, a zamiast tego możesz użyć dodatkowej funkcji przekazanej do Hooka useState(…)
. W praktyce — pewnie Ci się to zbyt często nie przyda.
Pytania?
Naucz się React na naszym szkoleniu! Jeśli chcesz na bieżąco śledzić kolejne części kursu React.js to koniecznie polub mnie na Facebooku i zapisz się na newsletter.
Podsumowanie
Omówiłem tutaj kilka niuansów związanych z Hookiem useState
w Reakcie. Możesz mieć teraz wrażenie, że to strasznie skomplikowana sprawa, skoro stworzyłem o tym aż dwa wpisy. tak naprawdę jednak Hooki to znaczne uproszczenie dla istniejących obecnie API i na pewno przyjemnie będzie Ci się z nich korzystało.
- React.js: Wprowadzenie do kursu od podstaw
- Poznaj React.js
- Pierwszy komponent w React.js
- Props czyli atrybuty w React.js
- Podział na komponenty w React.js
- Klasy jako komponenty React.js
- Interakcja z komponentami React.js
- Stan komponentów React.js
- State w React.js 2
- Metody cyklu życia komponentu w React.js
- React.js w przykładach: filtrowanie statycznej listy
- Tworzenie aplikacji React.js dzięki create-react-app
- React.js na GitHub Pages dzięki create-react-app
- Testowanie aplikacji React.js — podstawy Enzyme
- Testowanie React.js w Enzyme — props, state i interakcje
- Poprawne bindowanie funkcji w React.js
- Odpowiadam na pytania: Babel, ECMAScript, destrukturyzacja, onClick, className
- Komunikacja pomiędzy komponentami w React.js
- Komunikacja z API w React.js
- Formularze w React.js — kontrolowane komponenty
- Formularze w React.js — niekontrolowane komponenty
- Odpowiadam na pytania: props, nawiasy klamrowe, funkcje vs klasy, import react
- TDD w React.js z pomocą react-testing-library
- Flux i Redux: globalny store i jednokierunkowy przepływ danych
- React + Redux — kurs: wprowadzenie i podstawy
- React + Redux — filtrowanie listy, proste selektory
- Projektowanie komponentów: Presentational & Container Components
- Asynchroniczność w Redux: redux-thunk
- Kiedy używać state, a kiedy Redux?
- Nowe metody cyklu życia: getDerivedStateFromProps i getSnapshotBeforeUpdate
- Leniwe ładowanie komponentów w React dzięki import
- Higher Order Reducers — Redux i powtarzanie kodu
- React Hooks — wprowadzenie i motywacja
- React Hooks: useState, czyli stan w komponentach funkcyjnych
- React Hooks: useState — wiele stanów, callbacki i inne niuanse
- React Hooks: useEffect — efekty uboczne w komponencie
- React Hooks a żądania do API
- useReducer — przenoszenie logiki poza komponent
- useMemo, useCallback, czyli rozwiązanie problemów ze zmieniającymi się propsami
- Wady React Hooks
- React Hooks: Piszemy własne hooki!
jak sobie poradzić z problemem kiedy komponent funkcyjny zawiera wiele rożnych podkomponentów i liczba useState rośnie bardzo szybko?
Nie widzę problemu w tym, że komponenty mają jakiś stan.
Chodzi mi o to, czy jest jakiś pattern na przypadki, gdzie mamy np. wiele paneli w komponencie, które znajdują się w w wielu różnych stanach. Jak używam useState, to potem muszę ctrl+f używać, żeby się po takim potworku przemieszczać. Widziałem coś takiego w gicie u mnie w projekcie, ale nie potrafiłbym sensownie czegoś takiego zrefaktoryzować. Jedyne sensowne rozwiązanie jakie przychodzi mi do głowy to komponent klasowy, ale może można to lepiej zrobić?
W komponencie klasowym byłoby tak samo albo gorzej.
Jeśli masz wiele paneli, to zrób z tego może wiele komponentów?