Redux w React Native. Jak zarządza stanem aplikacji?

Sebastian
Sebastian
Front-end Developer

W trakcie rozwoju aplikacji z pewnością zauważasz, że im większa i bardziej złożona się staje, tym trudniej jest zarządzać stanami komponentów. Aby ułatwić to zadanie, inżynierowie Facebooka zaproponowali architekturę oraz bibliotekę Flux (jednokierunkowy przepływ danych). Redux stał się z kolei implementacją jej architektury, umieszczając informacje o stanie komponentów w jednym miejscu aplikacji.

Chociaż Redux jest najczęściej używany w połączeniu z React, jednak nie jest od niego uzależniony. Można zastosować go w aplikacjach opartych o inne frameworki frontendowe takie jak React, Vue i Angular lub czysty JavaScript.

W tym artykule przyjrzymy się bliżej podstawowym cechom Reduxa w kontekście z React.js. Dowiemy się również jak go zaimplementować w aplikacjach React Native.

Co to jest Redux?

Redux jest biblioteką JavaScript typu open source, a także jest przewidywalnym kontenerem do zarządzania stanem aplikacji. Można też go określić jako pamięć podręczną, do której w sposób ustrukturyzowany mogą uzyskać dostęp wszystkie komponenty. Pomaga pisać aplikacje, które zachowują się spójnie, działają w różnych środowiskach (klient, serwer i natywne) i są łatwe do przetestowania. 

Podstawowe zasady działania Redux:

  1. Cały stan aplikacji przechowywany jest w drzewie obiektów wewnątrz pojedynczego obiektu store
  2. Stan aplikacji jest tylko do odczytu. Jedynym sposobem na zmianę stanu jest wywołanie akcji, która zwraca obiekt, opisujący co powinno się stać.
  3. Zmiany wykonywane są w ramach czystych funkcji — tylko tworząc “czyste reduktory” zdefiniujesz, jak akcja wpłynie na stan aplikacji.

Kiedy Redux staje się potrzebny?

Gdy musisz zbudować dużą i złożoną aplikację proste zarządzanie stanem jako “rodzic-dziecko” staje się trudne, ponieważ istnieje wiele komponentów próbujących komunikować się między sobą. W takich przypadkach Redux okazuje się dobrym rozwiązaniem, ponieważ jego głównym zastosowaniem jest fakt, że można użyć jednego stanu aplikacji jako stanu głównego, a jednocześnie łatwo wchodzić w interakcję ze stanem z dowolnego komponentu reakcji, niezależnie od tego, czy to “rodzeństwo” czy “rodzice-dziecko”. 

Bez Redux chcąc przekazać np. dwa propsy w drzewie niżej, trzeba było wykonać pojedyncze działanie, przekazując dane  z komponentu nadrzędnego do komponentu/ów dziecięcych. Jest to pomocne w przypadku gdy musimy przekazać props tylko między dwoma komponentami w ramach szybszej  implementacji.

Redux umożliwia podpięcie każdego komponentu, nie wymaga to przekazywania danych między nimi, lecz z każdego komponentu można mieć dostęp do store. Jest to przepływ w jedną stronę, czyli jeśli chcemy wykonać zmianę store Redux z poziomu komponentu, wysyłamy do dispatchera akcję, który tę akcję wysyła do reduktora. On aktualizuje stan aplikacji i zaktualizowany stan wraca do komponentu.

redux flow

Działanie Redux polega generalnie na 3 podstawowych obszarach:

  • przetwarzanie akcji w oprogramowaniu pośredniczącym i reduktorach   
  • powiadamianie po wysłaniu akcji 
  • aktualizowanie komponentów interfejsu użytkownika na podstawie zmian stanu. 

Możesz rozważyć użycie Redux, jeśli stan aplikacji jest często aktualizowany, logika aktualizacji tego stanu może być złożona. Aplikacja ma średnią lub dużą bazę kodu i może nad nią pracować wiele osób. Szczególnie gdy potrzebujesz zobaczyć, jak ten stan jest aktualizowany w czasie.

Jeśli prowadzisz złożony projekt warto skorzystać z paczki startowej Reacta zawierającej więcej bibliotek, najpopularniejszą jest react-boilerplate z gotowym środowiskiem. Więcej na ten temat przeczytasz 👇

Z czego składa się Redux?

Redux można podzielić na kilka sekcji wykorzystywanych podczas budowania aplikacji. Poniżej wymienimy niektóre z nich.

➡️ Store

Store przechowuje cały stan aplikacji jako zwykły obiekt JavaScript. To w store przechowywane są dane “to do”. Store obsługuje również  bardziej złożone mechanizmy oprogramowania pośredniego (middleware).

➡️ Akcje

Akcje: to obiekty JavaScript, wysyłane za pomocą metody “dispatch” (reagowania).  Są jedynym źródłem informacji dla “store”. Oznacza to, że jeśli jakakolwiek zmiana stanu jest konieczna, zostanie ona wysłana za pośrednictwem akcji.

➡️ Reduktory

To funkcje, które określają, w jaki sposób zmienia się stan aplikacji w odpowiedzi na akcję. Podejmują akcję z ładunkiem jako argumentem i zwracają nowy stan na podstawie przekazanej do niego akcji. Najczęściej działa to w ten sposób: ktoś wywołuje akcję, dispatcher przekazuje akcję do reduktora, przekazując do niej aktualny stan oraz akcję, funkcja reduktor sprawdza typ przekazanej do niej akcji i w zależności jak jest ten typ, zwraca nową wersję stanu obiektu. Warto przy tym zwrócić uwagę to to, że  zwracamy nowy obiekt stanu zawsze w niezmienionej formie (ang. immutable). 

➡️ Oprogramowanie pośredniczące (Middleware)

To funkcje, które pozwalają nam rozszerzyć funkcjonalność Redux w naszej aplikacji. Oprogramowanie pośredniczące znajduje się pomiędzy akcją wysyłki a reduktorem, co oznacza, że ​​możemy wykonać jakąś inną funkcję, zanim wysyłka dotrze do reduktora.

Jak wdrożyć Redux w React Native?

Poniżej pokazujemy przykład tego jak wygląda wdrożenie Redux w aplikacji React Native.

1. Uruchamiamy Action Creator z pomocą dispatchera. 

2. Action Creator  zwraca Akcję (return) – Akcja jest obiektem, który zazwyczaj zawiera pola:

  •  type (unikalny ciąg znaków, po którym możemy zidentyfikować akcje w reduktorze) 
  • payload (dodatkowe informacje do akcji)

Na poniższej grafice Action Creator zwraca akcje/obiekt.

redux w react native (1)

Komponent LoginScreen umożliwia uruchomienie funkcji login za pomocą dispatchera (z użyciem hooka)

redux w react native (2)

3. Następnie akcja/obiekt trafia do reduktora, który na podstawie przekazanego pola “type” odnajduje odpowiednią instrukcję do wykonania i aktualizuje stan aplikacji.

Poniżej widzimy reduktor, w którym odbywa się aktualizacja store.

redux w react native (3)

4. Komponent, do którego propsów trafiają dane z Redux Store, po aktualizacji stora jest renderowany z nowymi danymi.

Zalety korzystania z Redux w React Native

Oto niektóre z głównych zalet korzystania z Redux w aplikacjach natywnych:

1. Łatwe usuwanie usterek z kodu

Debugowanie aplikacji jest proste dzięki Redux. Łatwo jest zrozumieć problemy z kodem i różne rodzaje błędów, które mogą pojawić się podczas produkcji, dzięki rejestrowaniu akcji i stanów.

2. Przewidywalny stan

Stan Redux jest zawsze przewidywalny. Ponieważ reduktory są czystymi funkcjami, zawsze dostarczają ten sam wynik, gdyż dostarczany jest do nich ten sam stan i akcja. Dotyczy to też niezmienności jego statusu. Pozwala to na obserwowanie efektów w czasie rzeczywistym za pomocą narzędzi Redux Dev.

3. Bezproblemowe utrzymanie

Redux ma ścisłe wytyczne dotyczące tego, jak powinien być zorganizowany kod, ułatwiając zrozumienie struktury dowolnego przykładu React Native Redux, co ułatwia jego utrzymanie. Taka ścisła organizacja kodu jest szczególnie potrzebna w przypadku dużych aplikacji, które przechodzą częste aktualizacje.

Zalety Redux w ReactPodsumowanie

Oczywiście przez lata pracy z Redux zauważono też jego pewne słabsze strony, jak jego złożoność, jeśli chodzi o używanie akcji logicznych manipulacji lub reduktorów. Również fakt, że stan trzeba ciągle aktualizować, powoduje, że proces ten na dłuższą metę tworzy kompilację prowadzącą do dużego użycia pamięci.

Obiektywnie o pracy z React.js wypowiadają się też nasi deweloperzy. Przeczytaj ciekawy artykuł na ten temat.

Mimo wszystko jednak Redux jest obecnie głównym narzędziem do zarządzania stanem komponentów, szczególnie tam, gdzie uruchamiane są produkty skierowane do konsumentów, jak aplikacje mobilne w React Native. 

Jeśli chciałbyś zapytać naszych inżynierów o wymagania techniczne w swoim projekcie, czy też dopytać jaki rodzaj zarządzania stanem komponentów byłby najlepszy, skontaktuj się z nami, chętnie odpowiemy na Twoje pytania i rozwiejemy wątpliwości technologiczne.