Mam dwa elementy.
- Komponent macierzysty
- Komponent potomny
Próbowałem wywołać metodę dziecka od rodzica, próbowałem w ten sposób, ale nie mogłem uzyskać rezultatu
class Parent extends Component {
render() {
return (
<Child>
<button onClick={Child.getAlert()}>Click</button>
</Child>
);
}
}
class Child extends Component {
getAlert() {
alert('clicked');
}
render() {
return (
<h1 ref="hello">Hello</h1>
);
}
}
Czy istnieje sposób na wywołanie metody dziecka od rodzica?
Uwaga: komponenty podrzędne i nadrzędne znajdują się w dwóch różnych plikach
javascript
reactjs
N8FURY
źródło
źródło
Odpowiedzi:
Po pierwsze, pozwólcie mi wyrazić, że generalnie nie jest to droga do rzeczy w React land. Zwykle to, co chcesz zrobić, to przekazać funkcjonalność dzieciom w rekwizytach i przekazywać powiadomienia od dzieci podczas wydarzeń (lub jeszcze lepiej:)
dispatch
.Ale jeśli musisz ujawnić metodę imperatywną na komponencie potomnym, możesz użyć referencji . Pamiętaj, że jest to właz ewakuacyjny i zwykle oznacza, że dostępny jest lepszy projekt.
Korzystanie z haków i składników funkcji (
>= [email protected]
)Dokumentacja dla
useImperativeHandle()
jest tutaj :Korzystanie ze składników klasy (
>= [email protected]
)Starsze API (
<= [email protected]
)Dla celów historycznych, oto styl oparty na wywołaniu zwrotnym, którego używałbyś w wersjach React przed 16.3:
źródło
connect
zwraca komponent wyższego rzędu, który otacza oryginalną instancję.getWrappedInstance()
Najpierw musisz zadzwonić do podłączonego komponentu, aby uzyskać oryginalny komponent. Następnie możesz wywołać w tym celu metody instancji.componentWillReceiveProps
, i użycie go jako wyzwalacza.Możesz użyć innego wzoru tutaj:
Robi to, aby ustawić
clickChild
metodę rodzica, gdy dziecko jest zamontowane. W ten sposób, gdy klikniesz przycisk w rodzicu, zadzwoni on,clickChild
który wywołuje dzieckogetAlert
.Działa to również wtedy, gdy twoje dziecko jest owinięte,
connect()
więc nie potrzebujeszgetWrappedInstance()
hacka.Zauważ, że nie możesz użyć
onClick={this.clickChild}
w rodzicu, ponieważ gdy rodzic jest renderowany, dziecko nie jest zamontowane, więcthis.clickChild
nie jest jeszcze przypisane. KorzystanieonClick={() => this.clickChild()}
jest w porządku, ponieważ po kliknięciu przyciskthis.clickChild
powinien być już przypisany.źródło
_this2.clickChild is not a function
dlaczego?https://facebook.github.io/react/tips/expose-component-functions.html aby uzyskać więcej odpowiedzi, zobacz tutaj Wywołanie metod w komponentach React child
Przyglądając się referencjom komponentu „przyczyny”, przełamujesz enkapsulację i uniemożliwiasz refaktoryzację tego komponentu bez dokładnego zbadania wszystkich używanych miejsc. Z tego powodu zdecydowanie zalecamy traktowanie referencji jako prywatnych dla komponentu, podobnie jak state.
Zasadniczo dane powinny być przekazywane w dół drzewa za pomocą rekwizytów. Istnieje kilka wyjątków od tego (np. Wywoływanie .focus () lub uruchamianie jednorazowej animacji, która tak naprawdę nie „zmienia” stanu), ale za każdym razem, gdy ujawniasz metodę o nazwie „set”, rekwizyty są zwykle lepszy wybór. Postaraj się, aby wewnętrzny komponent wejściowy martwił się jego rozmiarem i wyglądem, aby żaden z jego przodków tego nie robił.
źródło
Alternatywna metoda z useEffect:
Rodzic:
Dzieci:
źródło
Możemy użyć referencji w inny sposób, ponieważ-
Utworzymy element nadrzędny, który wyrenderuje
<Child/>
komponent. Jak widać, komponent, który będzie renderowany, musisz dodać atrybut ref i podać dla niego nazwę.Następnie
triggerChildAlert
funkcja znajdująca się w klasie nadrzędnej uzyska dostęp do właściwości refs tego kontekstu (gdytriggerChildAlert
funkcja zostanie uruchomiona, uzyska dostęp do odwołania potomnego i będzie mieć wszystkie funkcje elementu potomnego).Teraz komponent podrzędny, jak teoretycznie zaprojektowano wcześniej, będzie wyglądał następująco:
Oto kod źródłowy -
Nadzieja ci pomoże!
źródło
Jeśli robisz to po prostu dlatego, że chcesz, aby Dziecko miało cechę nadającą się do ponownego wykorzystania dla swoich rodziców, możesz zamiast tego rozważyć użycie tego za pomocą rekwizytów renderujących .
Ta technika faktycznie wywraca konstrukcję do góry nogami.
Child
Teraz zawija rodzica, więc mam przemianowano jąAlertTrait
poniżej. Zachowałem nazwęParent
ciągłości, chociaż tak naprawdę nie jest to teraz rodzic.W tym przypadku AlertTrait zapewnia jedną lub więcej cech, które przekazuje jako rekwizyty do dowolnego elementu podanego w
renderComponent
rekwizytach.Rodzic otrzymuje
doAlert
jako rekwizyt i może go wywołać w razie potrzeby.(Dla jasności nazwałem rekwizyt
renderComponent
w powyższym przykładzie. Ale w dokumentach React powiązanych powyżej po prostu go nazywająrender
.)Komponent Trait może renderować elementy otaczające obiekt nadrzędny w funkcji renderowania, ale nie renderuje niczego w obiekcie nadrzędnym. W rzeczywistości mógłby renderować rzeczy wewnątrz rodzica, jeśli przekazałby inny rekwizyt (np.
renderChild
) Rodzicowi, którego rodzic mógłby następnie użyć podczas metody renderowania.To nieco różni się od tego, o co poprosił PO, ale niektórzy ludzie mogą tu skończyć (tak jak my), ponieważ chcieli stworzyć cechę wielokrotnego użytku i uważali, że element potomny jest dobrym sposobem na zrobienie tego.
źródło
this.clickChild = click
ale wiele stoperów przejdzie przez wiele funkcji, więc musisz zapisać je wszystkie:this.watchRestartFuncs[watchId] = restartWatch
Możesz to łatwo osiągnąć w ten sposób
Kroki-
Z komponentu potomnego uzyskaj dostęp do tej zmiennej przy użyciu rekwizytów i wykonaj wybraną metodę, mając warunek if.
źródło
Używam
useEffect
haka, aby przezwyciężyć ból głowy związany z robieniem tego wszystkiego, więc teraz przekazuję zmienną dziecku w następujący sposób:źródło
Nie byłem zadowolony z żadnego z przedstawionych tutaj rozwiązań. W rzeczywistości istnieje bardzo proste rozwiązanie, które można wykonać przy użyciu czystego Javascript bez polegania na niektórych funkcjach React innych niż podstawowy obiekt rekwizytów - i daje to korzyść komunikacji w obu kierunkach (rodzic -> dziecko, dziecko -> rodzic). Musisz przekazać obiekt z komponentu nadrzędnego do komponentu podrzędnego. Ten obiekt nazywam „odniesieniem dwukierunkowym” lub w skrócie biRef. Zasadniczo obiekt zawiera odwołanie do metod w obiekcie nadrzędnym, które rodzic chce udostępnić. Komponent potomny dołącza metody do obiektu, który rodzic może wywołać. Coś takiego:
Inną zaletą tego rozwiązania jest to, że można dodać o wiele więcej funkcji w obiekcie nadrzędnym i podrzędnym, przekazując je z obiektu nadrzędnego dziecku przy użyciu tylko jednej właściwości.
Ulepszenie w stosunku do powyższego kodu polega na tym, aby nie dodawać funkcji nadrzędnej i podrzędnej bezpośrednio do obiektu biRef, ale raczej do elementów podrzędnych. Funkcje nadrzędne należy dodać do elementu o nazwie „rodzic”, a funkcje podrzędne należy dodać do elementu o nazwie „dziecko”.
Umieszczając funkcje nadrzędne i podrzędne w oddzielnych elementach obiektu biRef, będziesz mieć czystą separację między nimi i łatwo zobaczysz, które należą do nadrzędnego lub podrzędnego. Pomaga to również zapobiec przypadkowemu zastąpieniu przez element podrzędny funkcji nadrzędnej, jeśli ta sama funkcja pojawia się w obu.
Ostatnią rzeczą jest to, że jeśli zauważysz, komponent nadrzędny tworzy obiekt biRef za pomocą var, podczas gdy komponent potomny uzyskuje do niego dostęp poprzez obiekt rekwizytów. Może być kuszące, aby nie definiować obiektu biRef w obiekcie nadrzędnym i uzyskiwać do niego dostęp od jego obiektu nadrzędnego za pomocą własnego parametru rekwizytów (co może mieć miejsce w hierarchii elementów interfejsu użytkownika). Jest to ryzykowne, ponieważ dziecko może uważać, że funkcja, którą wywołuje na rodzicu, należy do rodzica, kiedy może faktycznie należeć do dziadka. Nie ma w tym nic złego, o ile jesteś tego świadomy. O ile nie masz powodu, aby wspierać hierarchię poza relacją rodzic-dziecko, najlepiej utworzyć biRef w komponencie nadrzędnym.
źródło
Możesz dokonać inwersji dziedziczenia (spójrz tutaj: https://medium.com/@franleplant/react-higher-order-components-in-depth-cf9032ee6c3e ). W ten sposób masz dostęp do instancji komponentu, który chcesz zawinąć (dzięki czemu będziesz mieć dostęp do jego funkcji)
źródło
Myślę, że najbardziej podstawowym sposobem wywoływania metod jest ustawienie żądania na komponencie potomnym. Następnie, gdy tylko dziecko obsługuje żądanie, wywołuje metodę wywołania zwrotnego w celu zresetowania żądania.
Mechanizm resetowania jest niezbędny, aby móc wysłać to samo żądanie wiele razy po sobie.
W komponencie nadrzędnym
W metodzie renderowania elementu nadrzędnego:
Rodzic potrzebuje 2 metod, aby komunikować się ze swoim dzieckiem w 2 kierunkach.
W komponencie potomnym
Dziecko aktualizuje swój stan wewnętrzny, kopiując żądanie z rekwizytów.
Następnie w końcu obsługuje żądanie i wysyła reset do rodzica:
źródło
Innym sposobem wyzwalania funkcji potomnej od rodzica jest użycie
componentDidUpdate
funkcji w komponencie potomnym. Przekazuję rekwizyttriggerChildFunc
od rodzica do dziecka, którym początkowo jestnull
. Wartość zmienia się w funkcję po kliknięciu przycisku, a dziecko zauważa zmianęcomponentDidUpdate
i wywołuje własną funkcję wewnętrzną.Ponieważ prop
triggerChildFunc
zmienia się w funkcji, otrzymujemy również wywołanie zwrotne do rodzica. Jeśli rodzic nie musi wiedzieć, kiedy funkcja jest wywoływana, wartośćtriggerChildFunc
może na przykład zmienić znull
natrue
zamiast.CodePen: https://codepen.io/calsal/pen/NWPxbJv?editors=1010
źródło
Oto moje demo: https://stackblitz.com/edit/react-dgz1ee?file=styles.css
Używam
useEffect
do wywołania metod komponentu potomnego. Próbowałem z,Proxy and Setter_Getter
ale zdecydowanieuseEffect
wydaje się być wygodniejszym sposobem na wywołanie metody potomnej od rodzica. AbyProxy and Setter_Getter
go użyć , wydaje się, że istnieje pewna subtelność, którą należy najpierw pokonać, ponieważ element najpierw renderowany jest elementem objectLike poprzezref.current return => <div/>
specyfikę. Jeśli chodzi o touseEffect
, możesz także wykorzystać to podejście, aby ustawić stan rodzica w zależności od tego, co chcesz zrobić z dziećmi.W linku do dema, który podałem, znajdziesz mój pełny kod ReactJS z moimi szkicami w środku, dzięki czemu możesz docenić przebieg mojego rozwiązania.
Dostarczam ci mój fragment ReactJS tylko z odpowiednim kodem. :
źródło
Jesteśmy zadowoleni z niestandardowego haka, który nazywamy
useCounterKey
. Po prostu ustawia counterKey lub klucz, który liczy się od zera. Zwracana funkcja resetuje klawisz (tzn. Przyrost). (Uważam, że jest to najbardziej idiomatyczny sposób resetowania komponentu w React - wystarczy uderzyć klawiszem).Jednak ten haczyk działa również w każdej sytuacji, w której chcesz wysłać klientowi jednorazową wiadomość, aby coś zrobić. Np. Używamy go do skupienia kontroli nad dzieckiem na określonym zdarzeniu nadrzędnym - po prostu automatycznie ustawia ostrość za każdym razem, gdy klucz jest aktualizowany. (Jeśli potrzeba więcej rekwizytów, można je ustawić przed zresetowaniem klucza, aby były dostępne, gdy zdarzenie się wydarzy.)
Ta metoda ma trochę krzywej uczenia się b / c, nie jest tak prosta jak typowa procedura obsługi zdarzeń, ale wydaje się najbardziej idiomatycznym sposobem radzenia sobie z tym w React, który znaleźliśmy (ponieważ klawisze już działają w ten sposób). Zdecyduj się na opinie na temat tej metody, ale działa ona dobrze!
Przykładowe zastosowania:
( Podziękowania dla Kent Dodds za koncepcję counterKey .)
źródło
Oto błąd? uważać: zgadzam się z rozwiązaniem rossipedia za pomocą forwardRef, useRef, useImperativeHandle
W Internecie jest kilka dezinformacji, które mówią, że referencje można tworzyć tylko z komponentów klasy React, ale rzeczywiście można użyć komponentów funkcji, jeśli użyje się wyżej wspomnianych haków. Uwaga: haki zadziałały dla mnie dopiero po zmianie pliku, aby nie używał on funkcjiRouter () podczas eksportowania komponentu. To znaczy zmiana z
zamiast tego być
Z perspektywy czasu metoda withRouter () i tak nie jest potrzebna w przypadku takiego komponentu, ale zwykle nic nie szkodzi w jego posiadaniu. Mój przypadek użycia polega na tym, że utworzyłem komponent do utworzenia tabeli do obsługi przeglądania i edycji wartości konfiguracji, i chciałem móc powiedzieć temu komponentowi potomnemu, aby zresetował jego wartości stanu za każdym razem, gdy wciśnięty został przycisk resetowania formularza nadrzędnego. UseRef () nie mógł poprawnie pobrać ref lub ref.current (ciągle uzyskiwał wartość null), dopóki nie usunęłem withRouter () z pliku zawierającego mój komponent potomny TableConfig
źródło