Właśnie zacząłem pracę z ReactJS i trochę utknąłem w moim problemie.
Moja aplikacja to zasadniczo lista z filtrami i przycisk do zmiany układu. W tej chwili używam trzy składniki: <list />
, < Filters />
a <TopBar />
teraz oczywiście przy zmianie ustawień < Filters />
Chcę wywołać jakąś metodę w <list />
celu zaktualizowania mój pogląd.
Jak sprawić, by te 3 komponenty współdziałały ze sobą, czy też potrzebuję jakiegoś globalnego modelu danych, w którym mogę po prostu wprowadzić zmiany?
javascript
reactjs
woutr_be
źródło
źródło
Odpowiedzi:
Najlepsze podejście zależy od tego, jak planujesz rozmieścić te komponenty. Kilka przykładowych scenariuszy, które przychodzą teraz na myśl:
<Filters />
jest elementem potomnym<List />
<Filters />
i<List />
są dziećmi elementu nadrzędnego<Filters />
i<List />
żyją całkowicie w oddzielnych składnikach głównych.Mogą istnieć inne scenariusze, o których nie myślę. Jeśli twoje nie mieści się w tych, daj mi znać. Oto kilka bardzo przybliżonych przykładów radzenia sobie z dwoma pierwszymi scenariuszami:
Scenariusz nr 1
Można przekazać moduł obsługi od
<List />
do<Filters />
, który można następnie wywołać wonChange
zdarzeniu w celu przefiltrowania listy przy użyciu bieżącej wartości.JSFiddle dla # 1 →
Scenariusz nr 2
Podobnie jak w scenariuszu nr 1, ale komponent nadrzędny będzie tym, który przekazuje funkcję modułu obsługi do
<Filters />
i przekaże przefiltrowaną listę do<List />
. Bardziej podoba mi się ta metoda, ponieważ oddziela ją<List />
od<Filters />
.JSFiddle dla # 2 →
Scenariusz nr 3
Gdy komponenty nie mogą komunikować się między jakimkolwiek rodzajem relacji rodzic-dziecko, dokumentacja zaleca skonfigurowanie globalnego systemu zdarzeń .
źródło
updateFilter
do<Filters />
i szyku, jakitems
się<List />
. Możesz użyć tych elementów potomnych u innych rodziców o różnych zachowaniach, razem lub solo. Na przykład, jeśli chcesz wyświetlić listę dynamiczną, ale nie potrzebujesz filtrowania.Istnieje wiele sposobów komunikacji między komponentami. Niektóre mogą być dostosowane do twojej skrzynki użytkownika. Oto lista niektórych, które uznałem za przydatne.
Reagować
Bezpośrednia komunikacja rodzic / dziecko
W tym przypadku komponent potomny wywoła wywołanie zwrotne dostarczone przez rodzica z wartością, a rodzic będzie mógł uzyskać wartość dostarczoną przez dzieci w rodzicu.
Jeśli tworzysz funkcję / stronę swojej aplikacji, lepiej jest mieć samotnego rodzica zarządzającego wywołaniami zwrotnymi / stanem (zwanym także
container
lubsmart component
), a wszystkie dzieci muszą być bezpaństwowcami. W ten sposób możesz łatwo „udostępnić” stan rodzica każdemu dziecku, które tego potrzebuje.Kontekst
Kontekst React pozwala na zachowanie stanu w katalogu głównym hierarchii komponentów i umożliwia łatwe wstrzykiwanie tego stanu do bardzo głęboko zagnieżdżonych komponentów, bez konieczności przekazywania rekwizytów do wszystkich komponentów pośrednich.
Do tej pory kontekst był funkcją eksperymentalną, ale nowy interfejs API jest dostępny w React 16.3.
Konsument używa wzorca renderowania / funkcji potomnych
Sprawdź ten post na blogu, aby uzyskać więcej informacji.
Przed React 16.3, zalecałbym używanie transmisji telewizyjnej, która oferuje dość podobny interfejs API i używanie wcześniejszego kontekstowego interfejsu API.
Portale
Skorzystaj z portalu, jeśli chcesz trzymać dwa komponenty blisko siebie, aby komunikować się za pomocą prostych funkcji, takich jak w normalnym obiekcie nadrzędnym / podrzędnym, ale nie chcesz, aby te 2 składniki miały relację nadrzędny / podrzędny w DOM, ponieważ implikowanych ograniczeń wizualnych / CSS (takich jak indeks Z, krycie ...).
W takim przypadku możesz użyć „portalu”. Istnieją różne biblioteki reagujące za pomocą portali , zwykle używanych do modałów , wyskakujących okienek, podpowiedzi ...
Rozważ następujące:
Po wygenerowaniu może wygenerować następujący DOM
reactAppContainer
:Więcej informacji tutaj
Automaty
Definiujesz gdzieś szczelinę, a następnie wypełniasz ją z innego miejsca drzewa renderowania.
Jest to trochę podobne do portali, z tym że wypełniona zawartość będzie renderowana w zdefiniowanym gnieździe, podczas gdy portale generalnie renderują nowy węzeł dom (często dzieci dokumentu.body)
Sprawdź bibliotekę reaguj-zapełnij szczelinę
Autobus zdarzeń
Jak stwierdzono w dokumentacji React :
Istnieje wiele rzeczy, których możesz użyć do skonfigurowania magistrali zdarzeń. Możesz po prostu utworzyć tablicę detektorów, a po opublikowaniu zdarzenia wszyscy detektory otrzymaliby zdarzenie. Lub możesz użyć czegoś takiego jak EventEmitter lub PostalJs
Strumień
Strumień jest zasadniczo magistralą zdarzeń, z tym wyjątkiem, że odbiorniki zdarzeń są sklepami. Jest to podobne do podstawowego systemu magistrali zdarzeń, z tym wyjątkiem, że stan jest zarządzany poza React
Oryginalna implementacja Fluxa wygląda jak próba hackowania Event-sourcingu.
Redux jest dla mnie implementacją Flux, która jest najbliższa pozyskiwaniu zdarzeń, ma wiele zalet związanych z pozyskiwaniem zdarzeń, takich jak możliwość podróżowania w czasie. Nie jest ściśle powiązany z React i może być również używany z innymi bibliotekami widoków funkcjonalnych.
Samouczek wideo Redhead firmy Egghead jest naprawdę fajny i wyjaśnia, jak działa wewnętrznie (jest naprawdę prosty).
Kursory
Kursory pochodzą z ClojureScript / Om i są szeroko stosowane w projektach React. Pozwalają zarządzać stanem poza React i pozwalają wielu komponentom na dostęp do odczytu / zapisu do tej samej części stanu, bez konieczności posiadania wiedzy na temat drzewa komponentów.
Istnieje wiele implementacji, w tym ImmutableJS , React-cursors i Omniscient
Edycja 2016 : wydaje się, że ludzie zgadzają się, że kursory działają dobrze w przypadku mniejszych aplikacji, ale nie skaluje się dobrze w złożonych aplikacjach. Om Next nie ma już kursorów (chociaż to Om początkowo wprowadził tę koncepcję)
Architektura wiązu
Architektura Elm to architektura zaproponowała być wykorzystywane przez języku Elm . Nawet jeśli Elm nie jest ReactJS, architektura Elm może być również wykonana w React.
Dan Abramov, autor Redux, wykonał implementację architektury Elm przy użyciu React.
Zarówno Redux, jak i Elm są naprawdę świetne i mają tendencję do wzmacniania koncepcji pozyskiwania zdarzeń na froncie, umożliwiając debugowanie w czasie, cofanie / ponawianie, odtwarzanie ...
Główna różnica między Redux a Elm polega na tym, że Elm jest o wiele bardziej rygorystyczny w zarządzaniu stanem. W Elm nie możesz mieć stanu lokalnego komponentu ani haków montowania / odmontowywania, a wszystkie zmiany DOM muszą być wywoływane przez globalne zmiany stanu. Architektura wiązów proponuje skalowalne podejście, które pozwala obsłużyć WSZYSTKIE stany wewnątrz jednego niezmiennego obiektu, podczas gdy Redux proponuje podejście, które zaprasza do obsługi WIĘKSZOŚCI stanu w pojedynczym niezmiennym obiekcie.
Podczas gdy koncepcyjny model Elm jest bardzo elegancki, a architektura pozwala dobrze skalować się w dużych aplikacjach, w praktyce może być trudny lub wymagać większej liczby elementów do wykonania prostych zadań, takich jak skupienie się na danych wejściowych po zamontowaniu lub integracja z istniejącą biblioteką z interfejsem imperatywnym (tj. wtyczką JQuery). Powiązany problem .
Również architektura Elm wymaga większej liczby kodów. Pisanie nie jest takie pełne i skomplikowane, ale myślę, że architektura Elm jest bardziej odpowiednia dla języków o typie statycznym.
FRP
Biblioteki takie jak RxJS, BaconJS lub Kefir mogą być używane do tworzenia strumieni FRP do obsługi komunikacji między komponentami.
Możesz spróbować na przykład Rx-React
Myślę, że używanie tych bibliotek jest dość podobne do używania tego, co oferuje język ELM z sygnałami .
Struktura CycleJS nie używa ReactJS, ale używa vdom . Ma wiele podobieństw z architekturą Elm (ale jest łatwiejszy w użyciu, ponieważ pozwala na haczyki vdom) i używa RxJs intensywnie zamiast funkcji i może być dobrym źródłem inspiracji, jeśli chcesz używać FRP z Reagować. Filmy z CycleJs Egghead są miłe, aby zrozumieć, jak to działa.
CSP
CSP (Communicating Sequential Processes) są obecnie popularne (głównie ze względu na Go / goroutines i core.async / ClojureScript), ale można ich używać również w javascript z JS-CSP .
James Long nakręcił film wyjaśniający, jak można go używać z React.
Sagi
Saga to koncepcja zaplecza, która pochodzi ze świata DDD / EventSourcing / CQRS, zwana także „menedżerem procesów”. Jest popularyzowany przez projekt redux-saga , głównie jako zamiennik redux-thunk do obsługi efektów ubocznych (tj. Wywołań API itp.). Większość ludzi uważa obecnie, że służy to jedynie do działań niepożądanych, ale tak naprawdę chodzi raczej o oddzielenie komponentów.
Jest to raczej komplement dla architektury Flux (lub Redux) niż całkowicie nowy system komunikacji, ponieważ saga emituje akcje Flux na końcu. Chodzi o to, że jeśli masz widget1 i widget2 i chcesz, aby były one oddzielone, nie możesz strzelać do akcji widget2 z widget1. Dzięki temu widżet1 wykonuje tylko te akcje strzelania, które są skierowane na siebie, a saga jest „procesem w tle”, który nasłuchuje akcji widget1 i może wywoływać akcje skierowane na widget2. Saga jest punktem łączącym 2 widżety, ale widżety pozostają oddzielone.
Jeśli jesteś zainteresowany, spójrz na moją odpowiedź tutaj
Wniosek
Jeśli chcesz zobaczyć przykład tej samej małej aplikacji używającej tych różnych stylów, sprawdź gałęzie tego repozytorium .
Nie wiem, która opcja jest najlepsza na dłuższą metę, ale bardzo podoba mi się to, jak Flux wygląda jak pozyskiwanie zdarzeń.
Jeśli nie znasz koncepcji pozyskiwania zdarzeń , zapoznaj się z tym bardzo pedagogicznym blogiem: Przekształcanie bazy danych na lewą stronę za pomocą apache Samza , należy przeczytać, aby zrozumieć, dlaczego Flux jest fajny (ale może to również dotyczyć FRP )
Myślę, że społeczność zgadza się, że najbardziej obiecującą implementacją Fluxa jest Redux , który stopniowo zapewni bardzo produktywne doświadczenie programistyczne dzięki gorącemu przeładowaniu. Imponujące kodowanie na żywo ala Bret Victor's Inventing on Principle jest możliwe!
źródło
OK, jest kilka sposobów, aby to zrobić, ale chcę skupić się wyłącznie na korzystaniu ze sklepu za pomocą Redux, co znacznie ułatwi ci życie w takich sytuacjach, zamiast dać ci szybkie rozwiązanie tylko w tym przypadku, użycie czystego React skończy się bałaganem w naprawdę duża aplikacja i komunikacja między komponentami staje się coraz trudniejsza wraz z rozwojem aplikacji ...
Więc co Redux robi dla ciebie?
Redux przypomina lokalną pamięć w aplikacji, z której można korzystać zawsze, gdy potrzebujesz danych do wykorzystania w różnych miejscach aplikacji ...
Zasadniczo pomysł Redux pochodzi z flux pierwotnie, ale z pewnymi fundamentalnymi zmianami, w tym koncepcją posiadania jednego źródła prawdy poprzez stworzenie tylko jednego sklepu ...
Spójrz na poniższy wykres, aby zobaczyć różnice między Flux i Redux ...
Rozważ zastosowanie Redux w swojej aplikacji od samego początku, jeśli aplikacja wymaga komunikacji między komponentami ...
Pomocne może być również przeczytanie tych słów z Dokumentacji Redux na początek:
źródło
datepicker
(jako komponentu) i ten komponent można załadować z wielu komponentów mieszkających na tej samej stronie, to skąddatepicker
komponent wiedziałby, którą akcję wysłać do redux? To jest istota problemu, łącząc działanie w jednym składniku BTO inny i nie każdy inny komponent . (weź pod uwagę, żedatepicker
sam jest głębokim, głębokim składnikiem w samym składniku modalnym)redux
i tego, co możesz przechowywać, ale JAK przekazać akcję głęboko w dół do tego, co musi ją uruchomić. Skąd głęboki składnik wie, co DOKŁADNIE należy uruchomić? ponieważ w tym przykładzie podałem ogólny komponent, który powinien wyzwalać określony reduktor, w zależności od scenariusza, więc może to być inny reduktor, ponieważ dla każdego komponentu można zastosować modal datepicker .Tak sobie z tym poradziłem.
Załóżmy, że masz <select> na miesiąc i <select> na dzień . Liczba dni zależy od wybranego miesiąca.
Obie listy są własnością trzeciego obiektu, lewego panelu. Zarówno <select> są również dziećmi leftPanel <div>
Jest to gra z wywołaniami zwrotnymi i programami obsługi w LeftPanel komponencie .
Aby to przetestować, po prostu skopiuj kod do dwóch oddzielnych plików i uruchom plik index.html . Następnie wybierz miesiąc i zobacz, jak zmienia się liczba dni.
date.js
I HTML do uruchamiania lewego panelu index.html
źródło
Widziałem, że na pytanie już udzielono odpowiedzi, ale jeśli chcesz dowiedzieć się więcej szczegółów, istnieją w sumie 3 przypadki komunikacji między komponentami :
źródło
Rozszerzając odpowiedź @MichaelLaCroix, gdy w scenariuszu komponenty nie mogą komunikować się między jakimkolwiek rodzicielskim stosunkiem-dzieckiem, dokumentacja zaleca ustanowienie globalnego systemu zdarzeń.
W przypadku
<Filters />
i<TopBar />
nie mają żadnego związku z powyższym, prosty globalny emiter może być stosowany tak:componentDidMount
- Subskrybuj wydarzeniecomponentWillUnmount
- Anuluj subskrypcję wydarzeniaKod React.js i EventSystem
EventSystem.js
NotificationComponent.js
źródło
Istnieje taka możliwość, nawet jeśli nie są relacjami rodzic - dziecko - i to jest Flux. Istnieje całkiem dobra (dla mnie osobiście) implementacja tego o nazwie Alt.JS (z Alt-Container).
Na przykład możesz mieć pasek boczny, który zależy od tego, co jest ustawione w szczegółach komponentu. Komponentowy pasek boczny jest połączony z SidebarActions i SidebarStore, natomiast Details to DetailsActions i DetailsStore.
Możesz użyć AltContainer w ten sposób
Który trzymałby sklepy (no cóż, mógłbym użyć propozycji „store” zamiast „store”). Teraz {this.props.content} MOŻE BYĆ Szczegóły w zależności od trasy. Powiedzmy, że / Details przekierowuje nas do tego widoku. Szczegóły zawierałyby na przykład pole wyboru, które zmieniałoby element paska bocznego z X na Y, gdyby był zaznaczony.
Technicznie nie ma między nimi żadnego związku i trudno byłoby obejść się bez przepływu. ALE Z TYM, że jest to raczej łatwe.
Przejdźmy teraz do DetailsActions. Stworzymy tam
i DetailsStore
A teraz tutaj zaczyna się magia.
Jak widać, istnieje SideLAdener do SidebarActions.ComponentStatusChanged, który zostanie użyty JEŻELI zostanie użyty setSiteComponent.
teraz w SidebarActions
Mamy coś takiego. Wyśle ten obiekt na wezwanie. Zostanie on wywołany, jeśli zostanie użyty setSiteComponent w sklepie (którego można użyć w komponencie na przykład podczas przełączania onChange na przycisku itp.)
Teraz w SidebarStore będziemy mieli
Teraz możesz zobaczyć, że będzie czekać na DetailsStore. Co to znaczy? mniej więcej oznacza to, że ta metoda musi poczekać na aktualizację DetailsStoreto, zanim będzie mogła się zaktualizować.
tl; dr One Store nasłuchuje metod w sklepie i wyzwoli akcję z akcji komponentu, która zaktualizuje swój własny sklep.
Mam nadzieję, że może ci to jakoś pomóc.
źródło
Jeśli chcesz zbadać opcje komunikacji między komponentami i poczujesz, że staje się to coraz trudniejsze, możesz rozważyć zastosowanie dobrego wzorca projektowego: Flux .
Jest to po prostu zbiór reguł, które definiują sposób przechowywania i mutowania stanu aplikacji i używania go do renderowania komponentów.
Istnieje wiele implementacji Flux, a oficjalna implementacja Facebooka jest jedną z nich. Chociaż jest uważany za ten, który zawiera większość kodu typu „Boilerplate”, ale łatwiej go zrozumieć, ponieważ większość rzeczy jest jawna.
Niektóre inne alternatywy są speszyć kogoś fluxxor fluxible i Redux .
źródło
Kiedyś byłem tam, gdzie jesteś teraz, jako początkujący czasami czujesz się nie na miejscu, jak zareagować, aby to zrobić. Spróbuję rozwiązać ten sam sposób, w jaki teraz o tym myślę.
Stany są kamieniem węgielnym komunikacji
Zwykle sprowadza się to do sposobu zmiany stanów w tym komponencie, w twoim przypadku wskazujesz trzy komponenty.
<List />
: Który prawdopodobnie wyświetli listę elementów w zależności od filtra<Filters />
: Opcje filtrów, które zmienią twoje dane.<TopBar />
: Lista opcji.Aby zaaranżować całą tę interakcję, będziesz potrzebować wyższego komponentu nazwijmy go aplikacją, która przekaże akcje i dane do każdego z tych komponentów, aby na przykład wyglądać tak
Kiedy
setFilter
zostanie wywołany, wpłynie to na filterItem i ponownie wyrenderuje oba składniki ;. W przypadku, gdy nie jest to do końca jasne, podałem przykład z polem wyboru, w którym można wpisać jeden plik:źródło
Poniższy kod pomaga mi skonfigurować komunikację między dwojgiem rodzeństwa. Konfiguracja odbywa się nadrzędnie podczas wywołań render () i componentDidMount (). Jest oparty na https://reactjs.org/docs/refs-and-the-dom.html Mam nadzieję, że to pomaga.
źródło
Dziwnie nikt nie wspomniał
mobx
. Pomysł jest podobny doredux
. Jeśli mam fragment danych subskrybowanych przez wiele komponentów, mogę użyć tych danych do sterowania wieloma komponentami.źródło