Redux - wiele sklepów, dlaczego nie?

221

Jako uwaga: przeczytałem dokumentację dotyczącą Redux (także Baobab) i sporo zrobiłem z Google'a i testów.

Dlaczego tak mocno sugeruje się, że aplikacja Redux ma tylko jeden sklep?

Rozumiem zalety / wady konfiguracji z jednym sklepem w porównaniu z konfiguracją z wieloma sklepami ( na ten temat istnieje wiele pytań i odpowiedzi ).

IMO, ta decyzja architektoniczna należy do twórców aplikacji na podstawie potrzeb ich projektów. Dlaczego więc jest tak mocno sugerowane Redux, aż do tego stopnia, że ​​brzmi to obowiązkowo ( chociaż nic nie powstrzymuje nas przed tworzeniem wielu sklepów )?

EDYCJA: informacja zwrotna po konwersji do jednego sklepu

Po kilku miesiącach pracy z redux nad tym, co wielu uważa za złożone SPA, mogę powiedzieć, że struktura pojedynczego sklepu była czystą przyjemnością do pracy.

Kilka punktów, które mogą pomóc innym zrozumieć, dlaczego pojedynczy sklep a wiele sklepów jest spornym pytaniem w wielu, wielu przypadkach użycia:

  • jest niezawodny : używamy selektorów do przeglądania stanu aplikacji i uzyskiwania informacji kontekstowych. Wiemy, że wszystkie potrzebne dane są w jednym sklepie. Pozwala to uniknąć wszelkich pytań o to, gdzie mogą być problemy ze stanem.
  • jest szybki : nasz sklep ma obecnie blisko 100 reduktorów, jeśli nie więcej. Nawet przy tej liczbie tylko garść reduktorów przetwarza dane dla dowolnej wysyłki, pozostałe tylko zwracają poprzedni stan. Argument, że ogromny / złożony sklep ( liczba reduktorów ) jest powolny, jest dość dyskusyjny. Przynajmniej nie widzieliśmy żadnych problemów z wydajnością.
  • przyjazny dla debugowania : chociaż jest to najbardziej przekonujący argument, aby używać redux jako całości, dotyczy to również jednego sklepu lub wielu sklepów. Podczas tworzenia aplikacji z pewnością występują błędy stanu ( błędy programisty ), jest to normalne. PITA jest wtedy, gdy błędy te wymagają wielu godzin debugowania. Dzięki jednemu sklepowi ( i redux-loggerowi ) nigdy nie spędziliśmy więcej niż kilka minut na jakimkolwiek problemie ze stanem.

kilka wskazówek

Prawdziwe wyzwanie w budowaniu sklepu redux polega na podjęciu decyzji o jego strukturze . Po pierwsze, ponieważ zmiana struktury w dół drogi to tylko duży ból. Po drugie, ponieważ w dużej mierze determinuje to, w jaki sposób będziesz używać, i zapytania aplikacji o dane dla dowolnego procesu. Istnieje wiele sugestii dotyczących struktury sklepu. W naszym przypadku uznaliśmy za idealne:

{
  apis: {     // data from various services
    api1: {},
    api2: {},
    ...
  }, 
  components: {} // UI state data for each widget, component, you name it 
  session: {} // session-specific information
}

Mamy nadzieję, że ta opinia pomoże innym.

EDYCJA 2 - pomocne narzędzia sklepu

Dla tych z Was, którzy zastanawiają się, jak „łatwo” zarządzać jednym sklepem , który może szybko się skomplikować. Istnieją narzędzia, które pomagają wyodrębnić zależności strukturalne / logikę sklepu.

Istnieje Normalizr, który normalizuje dane na podstawie schematu. Następnie zapewnia interfejs do pracy z danymi i pobierania innych części danych id, podobnie jak Słownik.

Nie znając wówczas Normalizra, zbudowałem coś według tych samych zasad. relational-json przyjmuje schemat i zwraca interfejs oparty na tabeli ( trochę jak baza danych ). Zaletą relational-json jest to, że struktura danych dynamicznie odwołuje się do innych części danych ( zasadniczo można przesuwać dane w dowolnym kierunku, podobnie jak normalne obiekty JS ). Nie jest tak dojrzały jak Normalizr, ale od kilku miesięcy z powodzeniem go używam w produkcji.

Sebastien Daniel
źródło
4
Podoba mi się twoje podejście do struktury sklepu, z której korzystasz; Jak jednak radzisz sobie z mapowaniem zmian stanu interfejsu API na zmiany stanu składnika? Powiedzmy, że otrzymuję dane dotyczące konkretnej domeny z mojego interfejsu API. W jaki sposób przekłada się to na ogólną strukturę danych, którą można znaleźć w moich komponentach?
Diniden,
To, jak twoje komponenty mapują / wykorzystują dane sklepu, zależy od ciebie. Chociaż myślę, że nie rozumiem w pełni twojego pytania, czy mógłbyś rozwinąć lub rozpocząć sesję czatu?
Sebastien Daniel
2
Myślę, że pytanie brzmiałoby: czy twoje komponenty renderują cokolwiek ze stanu apis, czy tylko renderują wszystko, co jest w stanie komponentów. Podejrzewam, że jeśli udało Ci się TYLKO renderować ze stanu komponentu, to znalazłeś doskonały sposób na to, aby Twoje komponenty i kontenery mogły być wielokrotnie ponownie używane, nawet w obecności danych specyficznych dla domeny. Jeśli Twoje komponenty wyświetlają się częściowo ze stanu interfejsu API ORAZ ze stanu komponentu, to domyślam się, że używasz kontenerów specyficznych dla domeny do mapowania danych w apis na ogólne listy i operacje podstawowe, które rozumieją twoje komponenty.
Diniden,
2
Używam Redux w połączeniu z selektorami, które są w zasadzie zapamiętywanymi, funkcjonalnie czystymi mapującymi dane. Każdy komponent „reaguje” na przechowywanie aktualizacji, a jeśli zmiana jest dla niego istotna, „wybiera” dane i odpowiednio je renderuje. Tak, komponenty renderują TYLKO na podstawie tego, co jest dla nich ważne. Ale to nie tylko ze względu na Redux lub strukturę sklepu. Wynika to z połączenia niezmiennego magazynu danych, referencyjnego testu porównawczego zmian danych oraz czystego selektora, który pobiera dane, których potrzebuje komponent, w wymaganym formacie.
Sebastien Daniel
Hej @SebastienDaniel, czy możesz pokazać przykład, w jaki sposób wdrażasz sprawdzanie, czy każdy składnik robi, aby wiedzieć, czy zmiana w aktualizacji sklepu jest dla niego istotna? Mam na myśli, jeśli używasz jakiegoś ogólnego wzorca ... lub jeśli w każdym konkretnym przypadku sprawdzasz, czy dane związane ze składnikiem uległy zmianie.
John Bernardsson,

Odpowiedzi:

232

Zdarzają się przypadki, w których możesz korzystać z wielu sklepów (np. Jeśli masz problemy z wydajnością podczas aktualizowania list tysięcy elementów, które są wyświetlane na ekranie wiele razy na sekundę). To powiedziawszy, że jest to wyjątek i w większości aplikacji nigdy nie potrzebujesz więcej niż jednego sklepu.

Dlaczego akcentujemy to w dokumentach? Ponieważ większość osób pochodzących z Fluxa zakłada , że wiele sklepów jest rozwiązaniem modularnym. Jednak Redux ma na to inne rozwiązanie: skład reduktora.

Posiadanie wielu reduktorów, które są dalej podzielone na drzewo reduktorów, jest sposobem na utrzymanie aktualizacji modułowych w Redux. Jeśli nie rozpoznasz tego i wybierzesz wiele sklepów bez pełnego zrozumienia składu reduktora, stracisz wiele zalet architektury pojedynczego sklepu Redux:

  • Zastosowanie kompozycji reduktorów ułatwia wdrożenie „aktualizacji zależnych” a la waitForw Flux, pisząc reduktor ręcznie wywołując inne reduktory z dodatkowymi informacjami i w określonej kolejności.

  • W jednym sklepie bardzo łatwo jest utrzymać, nawodnić i odczytać stan. Renderowanie serwera i wstępne pobieranie danych jest trywialne, ponieważ istnieje tylko jedna pamięć danych, którą należy wypełnić i uwodnić na kliencie, a JSON może opisać jej zawartość bez obawy o identyfikator lub nazwę sklepu.

  • Jeden sklep umożliwia korzystanie z funkcji podróży w czasie Redux DevTools. Ułatwia także rozszerzenia społeczności, takie jak redux-undo lub redux-optimist, ponieważ działają one na poziomie reduktora. Takich „wzmacniaczy redukcji” nie można napisać dla sklepów.

  • Pojedynczy sklep gwarantuje, że subskrypcje są wywoływane dopiero po przetworzeniu wysyłki. Oznacza to, że do czasu powiadomienia słuchaczy stan został w pełni zaktualizowany. W wielu sklepach nie ma takich gwarancji. Jest to jeden z powodów, dla których Flux potrzebuje waitForkuli. W przypadku jednego sklepu nie jest to problem, który widzisz w pierwszej kolejności.

  • Przede wszystkim wiele sklepów jest niepotrzebnych w Redux (z wyjątkiem przypadków krawędzi wydajności, które i tak należy najpierw profilować). Dbamy o to, aby była to ważna kwestia w dokumentacji, dlatego zachęcamy do nauki kompozycji reduktora i innych wzorców Redux zamiast używania Redux tak, jakby to był Flux i utraty jego zalet.

Dan Abramov
źródło
11
Przyznaję, że nie rozumiałem pełnej przewagi / konieczności składu reduktora. Dzięki twojej odpowiedzi zrobiłem jeszcze trochę czytania i przykład (ponownie TodoMVC). Przy tak małym przykładzie trudno było zrozumieć faktyczną poprawę zapewnianą przez skład reduktora. Jednak przy odrobinie namysłu zysk na dużą skalę jest (teraz) oczywisty. Jeszcze raz dziękuję, świetna odpowiedź!
Sebastien Daniel,
4
@Sebastien Myślę, że lepszy jest przykład „koszyka”.
Dan Abramov,
3
Powoli wdrażam redux do tradycyjnej aplikacji (nie SPA). Korzystam ze sklepów wielopoziomowych dla każdej „całości”, którą przekonwertowałem na implementację React / Redux, dopóki cała aplikacja nie będzie mogła zostać zmodyfikowana, aby korzystała z tego samego sklepu.
Paul Knopf,
5
@DanAbramov Ciekawe, co zrobisz w sytuacji, gdy Twoja główna „aplikacja” prowadzi własny sklep Redux i importuje za pośrednictwem npm niezależną „aplikację”, która prowadzi własny oddzielny sklep Redux. Na przykład, jeśli jeden z innych zespołów w Twojej firmie ma jakąś usługę przesyłania wiadomości z interfejsem użytkownika, który chcesz pobrać bez zanieczyszczania sklepu tymi danymi.
natlee75
6
@ natlee75 „Niektóre uzasadnione powody używania wielu sklepów w Redux mogą obejmować: [...] Izolowanie aplikacji Redux jako komponentu w większej aplikacji, w którym to przypadku możesz chcieć utworzyć magazyn dla instancji składnika głównego.” From redux.js.org/docs/FAQ.html#store-setup-multiple-stores
Kevin
24

W niektórych bardzo dużych aplikacjach dla przedsiębiorstw z setkami lub tysiącami reduktorów często przydatne jest myślenie o różnych obszarach aplikacji jako całkowicie oddzielnych aplikacjach. W tych przypadkach (gdzie tak naprawdę jest wiele aplikacji, które mają wspólną nazwę domeny), korzystam z wielu sklepów.

Na przykład następujące wspólne obszary funkcjonalności traktuję jako osobne aplikacje:

  • Administrator
  • Analityka / dane w pulpitach nawigacyjnych
  • Zarządzanie rozliczeniami i przepływy zakupów
  • Zespół konta korporacyjnego / zarządzanie uprawnieniami

Jeśli którakolwiek z tych rzeczy jest niewielka, po prostu zachowaj ją jako część głównej aplikacji. Jeśli staną się bardzo duże (jak robią to niektóre narzędzia do zarządzania kontami i analizy przedsiębiorstw), rozdziel je.

Najlepszym sposobem zarządzania bardzo dużymi aplikacjami jest traktowanie ich jak wielu mniejszych aplikacji.

Jeśli Twoja aplikacja ma mniej niż ~ 50 000 LOC, prawdopodobnie zignoruj ​​tę radę i postępuj zgodnie z radą Dana.

Jeśli Twoja aplikacja ma ponad 1 milion LOC, prawdopodobnie powinieneś rozdzielać mini-aplikacje, nawet jeśli utrzymasz je w mono repo.

Eric Elliott
źródło
5

Ta decyzja architektoniczna należy do twórców aplikacji na podstawie potrzeb ich projektów

Żyjesz we własnym świecie. Spotykam się z ludźmi, którzy używają redux, ponieważ jest popularny, codziennie. Nie można sobie nawet wyobrazić, ile projektów zaczęto reduxing bez podejmowania decyzji. Nienawidzę podejść redux, ale musiałem z nich skorzystać, ponieważ inni programiści nie wiedzą nic więcej. To tylko epicka bańka napompowana przez Facebook.

  • To nie jest niezawodne, ponieważ części sklepu nie są izolowane.
  • Jest to nieefektywne, ponieważ klonujesz i przemierzasz hash trie. Gdy mutacje rosną arytmetycznie - złożoność rośnie geometrycznie. Nie można tego naprawić, refaktoryzując dowolne reduktory, selektory itp. Musisz podzielić trie.
  • Kiedy staje się powolny, nikt nie chce podzielić go na osobne aplikacje z osobnymi sklepami. Nikt nie chce wydawać pieniędzy na refaktoryzację. Ludzie zwykle przekształcają niektóre inteligentne komponenty w zrzut i to wszystko. Czy wiesz, jaka przyszłość czeka programistów redux? Będą utrzymywać te piekła.
  • Nie jest przyjazny do debugowania . Trudno jest debugować połączenia między wirtualnie izolowanymi częściami sklepu. Bardzo trudno jest nawet przeanalizować liczbę tych połączeń.

Wyobraźmy sobie, że masz kilka sklepów redux. Złamiesz jednokierunkowy przepływ danych. Natychmiast zorientujesz się, ile masz połączeń między sklepami. Możesz cierpieć z powodu tych połączeń, walcząc z depresjami kołowymi itp.

Pojedynczy niezmienny sklep z jednokierunkowym przepływem nie jest eliksirem dla każdej choroby. Jeśli nie chcesz zachować architektury projektu, i tak będziesz cierpieć.

puchu
źródło
Podobało mi się to, co powiedziałeś, i tutaj zadałem powiązane pytanie na ten temat. Czy mógłbyś na to spojrzeć, kiedy poświęcisz trochę czasu i podzielisz się swoją opinią? Pytanie zadałem w Reddit, ponieważ SO nie zachęca tutaj do takich pytań.
Arup Rakshit
3

Wiele sklepów może być pomocnych w następujących przypadkach użycia 1. Jeśli masz duże komponenty, które są od siebie niezależne pod względem struktury danych, zachowania, kontekstu aplikacji. Izolowanie tych komponentów ułatwia zarządzanie przepływem danych i aplikacji. Pomaga również w niezależnym opracowywaniu i konserwacji komponentów. 2. Problemy z wydajnością: nie jest to typowy przypadek użycia, ale jeśli niektóre komponenty są bardzo często aktualizowane i nie mają żadnego wpływu na inne komponenty, prawdopodobnie możesz wybrać inne sklepy.

We wszystkich innych przypadkach może nie być potrzeby posiadania wielu sklepów. Jak mówi Dan, tworzenie przemyślanych kompozycji reduktorów może okazać się lepszym rozwiązaniem.

newtonflash
źródło
Twoja wiadomość wygląda następująco: „używaj redux zawsze oprócz kilku przypadków” == „nie potrzebujesz architektury projektu z wyjątkiem kilku przypadków”. Jestem bardzo blisko rzeczywistości, jestem szczęśliwy.
puchu
2

dlaczego nie możemy korzystać z wielu sklepów za pomocą redux ????

Nie jest to konieczne w Redux, ponieważ separacja między domenami danych jest już osiągnięta przez podział pojedynczego reduktora na mniejsze reduktory.


Czy mogę czy powinienem utworzyć wiele sklepów? Czy mogę zaimportować bezpośrednio swój sklep i sam go użyć w komponentach?

Oryginalny wzorzec Flux opisuje posiadanie wielu „sklepów” w aplikacji, z których każda zawiera inny obszar danych domeny. Może to powodować problemy, takie jak konieczność posiadania jednego sklepu „waitFor” innego sklepu do aktualizacji.

Nie jest to konieczne w Redux, ponieważ separacja między domenami danych jest już osiągnięta przez podział pojedynczego reduktora na mniejsze reduktory.

Podobnie jak w przypadku kilku innych pytań, możliwe jest utworzenie wielu różnych sklepów Redux na stronie, ale zamierzonym wzorcem jest posiadanie tylko jednego sklepu. Posiadanie jednego sklepu umożliwia korzystanie z Redux DevTools, upraszcza utrwalanie i nawadnianie danych oraz upraszcza logikę subskrypcji.

Niektóre ważne powody używania wielu sklepów w Redux mogą obejmować:

Rozwiązanie problemu z wydajnością spowodowanego zbyt częstymi aktualizacjami pewnej części stanu, co zostało potwierdzone przez profilowanie aplikacji. Izolowanie aplikacji Redux jako komponentu w większej aplikacji, w takim przypadku możesz utworzyć magazyn dla instancji składnika głównego. Jednak tworzenie nowych sklepów nie powinno być twoim pierwszym instynktem, szczególnie jeśli pochodzisz z Flux. Spróbuj najpierw składu reduktora i korzystaj z wielu sklepów tylko wtedy, gdy nie rozwiąże to problemu.

Podobnie, chociaż możesz odwoływać się do instancji sklepu, importując ją bezpośrednio, nie jest to zalecany wzorzec w Redux. Jeśli utworzysz instancję sklepu i wyeksportujesz ją z modułu, stanie się ona singletonem. Oznacza to, że trudniej będzie izolować aplikację Redux jako składnik większej aplikacji, jeśli będzie to kiedykolwiek konieczne, lub włączyć renderowanie serwera, ponieważ na serwerze chcesz utworzyć osobne wystąpienia sklepu dla każdego żądania.

oficjalny dokument redux

Rizo
źródło
1

Posiadanie jednego sklepu w Redux jest naprawdę tym, czego potrzebujemy w wielu przypadkach. Obie korzystałem z Redux i Flux i wierzę, że Redux wykonuje to lepiej!

Nie zapominaj, że sklep znajduje się w obiekcie JavaScript, więc chociaż masz tylko jeden sklep, można go łatwo rozszerzyć i ponownie użyć, dla mnie posiadanie jednego sklepu znacznie ułatwia przechodzenie przez narzędzia programistyczne Redux i nie daje się pomylić duże aplikacje ...

Również koncepcja jednego sklepu naśladuje dla nas bazę danych, jedno źródło prawdy, które można zmienić i uzyskać do niej dostęp w pamięci przeglądarki ...

Jeśli cała aplikacja jest dobrze zarządzana, jeden sklep może wystarczyć do zarządzania całym stanem aplikacji ...

Alireza
źródło
3
Dlatego każdy powinien wierzyć, że pojedynczy sklep wykona pracę lepiej i nikt nie może wyjaśnić, dlaczego. Coś mi przypomina ...
puchu