- Załóżmy, że mam klasę React P, która renderuje dwie klasy potomne, C1 i C2.
- C1 zawiera pole wprowadzania. Odniosę się do tego pola wejściowego jako Foo.
- Moim celem jest pozwolić C2 reagować na zmiany w Foo.
Wymyśliłem dwa rozwiązania, ale żadne z nich nie jest w porządku.
Pierwsze rozwiązanie:
- Przypisywanie P państwem,
state.input
. - Utwórz
onChange
funkcję w P, która przyjmuje zdarzenie i ustawiastate.input
. - Przekaż to
onChange
C1 jako aprops
i pozwól C1 związaćthis.props.onChange
sięonChange
z Foo.
To działa. Ilekroć zmienia się wartość Foo, wyzwala a setState
w P, więc P będzie miał dane wejściowe do przekazania do C2.
Ale to nie wydaje się właściwe z tego samego powodu: ustawiam stan elementu nadrzędnego na podstawie elementu podrzędnego. Wydaje się, że zdradza to zasadę projektowania React: przepływ danych w jednym kierunku.
Czy tak powinienem to zrobić, czy może istnieje bardziej naturalne rozwiązanie React?
Drugie rozwiązanie:
Po prostu umieść Foo w P.
Ale czy to zasada projektowania, którą powinienem stosować, tworząc strukturę mojej aplikacji - umieszczając wszystkie elementy formularza w render
klasie najwyższego poziomu?
Podobnie jak w moim przykładzie, jeśli mam duży rendering C1, naprawdę nie chcę umieszczać całego render
C1 na render
P tylko dlatego, że C1 ma element form.
Jak mam to zrobić?
Odpowiedzi:
Więc jeśli dobrze cię rozumiem, twoje pierwsze rozwiązanie sugeruje, że utrzymujesz stan w swoim głównym komponencie? Nie mogę mówić za twórcami React, ale ogólnie uważam, że jest to właściwe rozwiązanie.
Utrzymanie stanu jest jednym z powodów (przynajmniej tak mi się wydaje), że React został stworzony. Jeśli kiedykolwiek wdrożyłeś własną stronę klienta ze wzorcem stanu do radzenia sobie z dynamicznym interfejsem użytkownika, który ma wiele wzajemnie zależnych elementów ruchomych, pokochasz React, ponieważ łagodzi on wiele bólu zarządzania stanem.
Utrzymując stan na wyższym poziomie w hierarchii i aktualizując go za pomocą zdarzeń, przepływ danych jest nadal prawie jednokierunkowy, po prostu reagujesz na zdarzenia w komponencie Root, tak naprawdę nie dostajesz tam danych przez wiązanie dwukierunkowe, mówisz komponentowi Root, że „hej, coś się tutaj wydarzyło, sprawdź wartości” lub przekazujesz stan niektórych danych w komponencie potomnym w celu aktualizacji stanu. Zmieniłeś stan w C1 i chcesz, aby C2 był tego świadomy, więc aktualizując stan w komponencie głównym i ponownie renderując, rekwizyty C2 są teraz zsynchronizowane, ponieważ stan został zaktualizowany w komponencie głównym i przekazany dalej .
źródło
C2
maszgetInitialState
dane i wewnątrz którychrender
używathis.state.data
?Po użyciu aplikacji React do zbudowania aplikacji chciałbym podzielić się przemyśleniami na temat pytania, które zadałem pół roku temu.
Polecam przeczytać
Pierwszy post jest niezwykle pomocny w zrozumieniu, w jaki sposób należy uporządkować aplikację React.
Flux odpowiada na pytanie, dlaczego powinieneś tak ustrukturyzować aplikację React (a nie jak to zrobić) ją ustrukturyzować). React to tylko 50% systemu, a dzięki Flux możesz zobaczyć cały obraz i zobaczyć, jak tworzą one spójny system.
Powrót do pytania
Jeśli chodzi o moje pierwsze rozwiązanie, to jest całkowicie OK, aby pozwolić handlerowi iść w przeciwnym kierunku, ponieważ dane wciąż idą w jednym kierunku.
Jednak to, czy zezwolenie funkcji obsługi na wywołanie setState w P może być prawidłowe, czy niepoprawne, w zależności od sytuacji.
Jeśli aplikacja jest prostym konwerterem Markdown, C1 jest surowym wejściem, a C2 wyjściem HTML, możesz pozwolić C1 wyzwalać setState w P, ale niektórzy mogą argumentować, że nie jest to zalecany sposób.
Jeśli jednak aplikacja jest listą czynności do wykonania, C1 stanowi dane wejściowe do utworzenia nowej czynności do wykonania, C2 jest to lista czynności do wykonania w HTML, prawdopodobnie prawdopodobnie chcesz, aby program obsługiwał przejście o dwa poziomy wyżej niż P - do
dispatcher
, co pozwala nastore
aktualizacjędata store
, które następnie przesyłają dane do P i wypełniają widoki. Zobacz ten artykuł Flux. Oto przykład: Flux - TodoMVCOgólnie wolę sposób opisany w przykładzie z listą rzeczy do zrobienia. Im mniej masz stanu w swojej aplikacji, tym lepiej.
źródło
Pięć lat później, wraz z wprowadzeniem React Hooks, istnieje teraz o wiele bardziej elegancki sposób korzystania z haka useContext.
Kontekst definiujesz w zasięgu globalnym, eksportujesz zmienne, obiekty i funkcje w komponencie nadrzędnym, a następnie zawijasz elementy podrzędne w aplikacji w podanym kontekście i importujesz wszystko, czego potrzebujesz w komponentach podrzędnych. Poniżej znajduje się dowód koncepcji.
Możesz uruchomić ten przykład w edytorze Code Sandbox.
źródło
Pierwsze rozwiązanie z zachowaniem stanu w komponencie nadrzędnym jest poprawne . Jednak w przypadku bardziej skomplikowanych problemów należy pomyśleć o bibliotece zarządzania stanem , najbardziej popularna jest biblioteka redux używana w funkcji reagowania.
źródło
Dziwi mnie, że w chwili pisania nie ma odpowiedzi na proste, idiomatyczne rozwiązanie React. Oto jeden (porównaj rozmiar i złożoność z innymi):
Każdy kontrolowany
input
(idiomatyczny sposób pracy z formularzami w React) aktualizuje stan nadrzędny w jegoonChange
wywołaniu zwrotnym i nadal niczego nie zdradza.Przyjrzyj się na przykład składnikowi C1. Czy widzisz jakąś znaczącą różnicę w sposobie?
C1
wbudowanyinput
komponent obsługuje zmiany stanu? Nie powinieneś, bo nie ma. Podnoszenie stanu i przekazywanie par wartość / onZmień pary jest idiomatyczne dla surowego React. Nie stosowanie referencji, jak sugerują niektóre odpowiedzi.źródło
this.state
, w renderowaniu brakowało zwrotu, a wiele składników musi być owiniętych w div lub coś takiego. Nie wiem, jak mi to umknęło, kiedy napisałem oryginalną odpowiedź. Musiał być błąd edycji.Nowsza odpowiedź z przykładem, który wykorzystuje
React.useState
Zalecane jest utrzymywanie stanu w komponencie nadrzędnym. Rodzic musi mieć do niego dostęp, ponieważ zarządza nim w dwóch elementach potomnych. Przeniesienie go do stanu globalnego, takiego jak zarządzanego przez Redux, nie jest zalecane z tego samego powodu, dla którego zmienna globalna jest ogólnie gorsza niż lokalna w inżynierii oprogramowania.
Gdy stan znajduje się w komponencie nadrzędnym, dziecko może je mutować, jeśli rodzic podaje dziecko
value
ionChange
moduł obsługi w rekwizytach (czasami nazywa się to łączem wartości lub wzorcem łącza stanu ). Oto jak zrobiłbyś to z hakami:Cały komponent nadrzędny będzie renderowany ponownie po zmianie danych wejściowych w obiekcie potomnym, co może nie stanowić problemu, jeśli jego ponowne nadanie jest małe / szybkie. Wydajność ponownego renderowania komponentu macierzystego nadal może stanowić problem w ogólnym przypadku (na przykład w dużych formularzach). Ten problem został rozwiązany w twoim przypadku (patrz poniżej).
Wzorzec stanu łącza i brak nadrzędnego renderowania są łatwiejsze do wdrożenia przy użyciu biblioteki innej firmy, takiej jak Hookstate - doładowanie
React.useState
obejmuje różne przypadki użycia, w tym również twoją. (Uwaga: Jestem autorem projektu).Oto jak by to wyglądało z Hookstate.
Child1
zmieni dane wejściowe,Child2
zareaguje na to.Parent
będzie utrzymywać stan, ale nie będzie renderować ponownie po zmianie stanu, tylkoChild1
iChild2
będzie.PS: istnieje wiele innych przykładów obejmujących podobne i bardziej skomplikowane scenariusze, w tym głęboko zagnieżdżone dane, sprawdzanie poprawności stanu, stan globalny z
setState
hakiem itp. Istnieje również pełna przykładowa aplikacja online , która wykorzystuje Hookstate i technikę wyjaśnioną powyżej.źródło
Powinieneś nauczyć się biblioteki Redux i ReactRedux, która uporządkuje twoje stany i rekwizyty w jednym sklepie i będziesz mieć do nich dostęp później w swoich komponentach.
źródło
Za pomocą React> = 16.3 możesz użyć ref i forwardRef, aby uzyskać dostęp do DOM-u dziecka od jego rodzica. Nie używaj już starej metody referencji.
Oto przykład z wykorzystaniem twojego przypadku:
Zobacz Refs i ForwardRef, aby uzyskać szczegółowe informacje na temat refs i forwardRef.
źródło
shouldComponentUpdate(nextProps, nextState)
Poniższy kod używa
@bound
adnotacji z ES.Nextbabel-plugin-transform-decorators-legacy
z BabelJS 6 i właściwości klasy (adnotacja ustawia tę wartość na funkcjach składowych podobnych do wiązania):źródło
Pojęcie przekazywania danych z rodzica na dziecko i odwrotnie jest wyjaśnione.
źródło