Tworzę aplikację, która w niektórych sytuacjach musi wyświetlać okno dialogowe potwierdzenia.
Powiedzmy, że chcę coś usunąć, a następnie wyślę akcję taką, deleteSomething(id)
aby jakiś reduktor przechwycił to zdarzenie i wypełnił okno dialogowe redukcji, aby je pokazać.
Moje wątpliwości pojawiają się po przesłaniu tego okna dialogowego.
- W jaki sposób ten komponent może wywołać prawidłowe działanie zgodnie z pierwszym wysłanym działaniem?
- Czy twórca akcji powinien obsługiwać tę logikę?
- Czy możemy dodać działania wewnątrz reduktora?
edytować:
aby było jaśniej:
deleteThingA(id) => show dialog with Questions => deleteThingARemotely(id)
createThingB(id) => Show dialog with Questions => createThingBRemotely(id)
Więc próbuję ponownie użyć komponentu okna dialogowego. Wyświetlanie / ukrywanie okna dialogowego nie jest problemem, ponieważ można to łatwo zrobić w reduktorze. To, co próbuję określić, to sposób wysłania akcji z prawej strony zgodnie z akcją rozpoczynającą przepływ z lewej strony.
javascript
modal-dialog
redux
react-redux
carlesba
źródło
źródło
Odpowiedzi:
Podejście, które sugeruję, jest nieco szczegółowe, ale udało mi się dość dobrze skalować w złożone aplikacje. Jeśli chcesz pokazać modal, uruchom akcję opisującą, który modal chcesz zobaczyć:
Wywołanie akcji w celu wyświetlenia modalu
(Ciągi mogą być oczywiście stałymi; używam ciągów wbudowanych dla uproszczenia.)
Pisanie reduktora w celu zarządzania stanem modalnym
Następnie upewnij się, że masz reduktor, który akceptuje tylko te wartości:
Wspaniały! Teraz, gdy wydasz akcję,
state.modal
zaktualizuje się, aby uwzględnić informacje o aktualnie widocznym oknie modalnym.Pisanie głównego elementu modalnego
W katalogu głównym hierarchii komponentów dodaj
<ModalRoot>
komponent, który jest podłączony do sklepu Redux. Będzie nasłuchiwałstate.modal
i wyświetlał odpowiedni komponent modalny, przekazując rekwizyty zstate.modal.modalProps
.Co my tu zrobiliśmy?
ModalRoot
odczytuje prądmodalType
imodalProps
odstate.modal
którego jest podłączony, i renderuje odpowiedni komponent, taki jakDeletePostModal
lubConfirmLogoutModal
. Każdy modal jest elementem!Pisanie określonych składników modalnych
Nie ma tu ogólnych zasad. Są tylko komponentami React, które mogą wywoływać akcje, czytać coś ze stanu sklepu i po prostu być modalne .
Na przykład,
DeletePostModal
może wyglądać następująco:DeletePostModal
Jest podłączony do sklepu, więc może wyświetlić tytuł posta i działa jak dowolnego podłączonego urządzenia: może wysyłką działań, w tymhideModal
przypadku konieczne jest, aby ukryć się.Wyodrębnianie elementu prezentacji
Byłoby niewygodne kopiowanie i wklejanie tej samej logiki układu dla każdego „określonego” modalu. Ale masz komponenty, prawda? Możesz więc wyodrębnić prezentację
<Modal>
komponent , który nie wie, co robią poszczególne modały, ale obsługuje ich wygląd.Następnie określone moduły, takie jak
DeletePostModal
można użyć do renderowania:To do ciebie należy wymyślenie zestawu rekwizytów
<Modal>
można zaakceptować w twojej aplikacji, ale wyobrażam sobie, że możesz mieć kilka rodzajów modów (np. Modal informacji, modal potwierdzenia itp.) I kilka stylów dla nich.Dostępność i ukrywanie na Click Outside lub Escape Key
Ostatnią ważną częścią modali jest to, że generalnie chcemy je ukryć, gdy użytkownik kliknie na zewnątrz lub naciśnie klawisz Escape.
Zamiast udzielać porad na temat wdrażania tego, sugeruję, abyś sam tego nie wdrażał. Trudno jest dobrze zrozumieć, biorąc pod uwagę dostępność.
Zamiast tego sugerowałbym, abyś użył dostępnego, modalnego komponentu, takiego jak
react-modal
. Jest całkowicie konfigurowalny, możesz umieścić w nim wszystko, co chcesz, ale poprawnie obsługuje dostępność, dzięki czemu niewidomi mogą nadal korzystać z twojego modalu.Możesz nawet owinąć
react-modal
własny<Modal>
który akceptuje rekwizyty specyficzne dla twoich aplikacji i generuje przyciski potomne lub inne treści. To wszystko tylko komponenty!Inne podejścia
Jest na to więcej niż jeden sposób.
Niektórzy ludzie nie lubią gadatliwości tego podejścia i wolą mieć
<Modal>
komponent, który mogą renderować bezpośrednio w swoich komponentach za pomocą techniki zwanej „portalami”. Portale pozwalają ci renderować komponent wewnątrz twojego, gdy faktycznie będzie renderowany w określonym miejscu w DOM, co jest bardzo wygodne w przypadku modałów.W rzeczywistości
react-modal
, o czym już wcześniej wspomniałem, robi to wewnętrznie, więc technicznie nie musisz nawet renderować tego z góry. Nadal uważam, że miło jest oddzielić modal, który chcę pokazać, od pokazującego go komponentu, ale możesz także używaćreact-modal
bezpośrednio z komponentów i pomijać większość tego, co napisałem powyżej.Zachęcam do rozważenia obu podejść, eksperymentowania z nimi i wybrania tego, co według ciebie będzie najlepsze dla Twojej aplikacji i zespołu.
źródło
modalProps
do akcji. Jest to jednak sprzeczne z zasadą utrzymywania stanu szeregowalnego. Jak mogę rozwiązać ten problem?Aktualizacja : React 16.0 wprowadził portale poprzez
ReactDOM.createPortal
linkAktualizacja : kolejne wersje React (Fibre: prawdopodobnie 16 lub 17) będą zawierać metodę tworzenia portali:
ReactDOM.unstable_createPortal()
linkUżyj portali
Pierwsza część odpowiedzi Dana Abramova jest w porządku, ale wiąże się z dużą ilością płyty kotłowej. Jak powiedział, możesz także korzystać z portali. Rozwinę trochę ten pomysł.
Zaletą portalu jest to, że okienko wyskakujące i przycisk pozostają bardzo blisko drzewa React, z bardzo prostą komunikacją nadrzędny / podrzędny za pomocą rekwizytów: możesz łatwo obsługiwać akcje asynchroniczne z portalami lub pozwolić rodzicowi dostosować portal.
Co to jest portal?
Portal pozwala na renderowanie bezpośrednio w
document.body
elemencie głęboko zagnieżdżonym w drzewie React.Chodzi o to, że na przykład renderujesz w ciele następujące drzewo React:
I dostajesz jako wynik:
inside-portal
Węzeł został przekłada się wewnątrz<body>
, a nie od jego normalnej głęboko zagnieżdżonej miejscu.Kiedy korzystać z portalu
Portal jest szczególnie pomocny do wyświetlania elementów, które powinny się znajdować na istniejących komponentach React: wyskakujące okienka, listy rozwijane, sugestie, punkty aktywne
Dlaczego warto korzystać z portalu?
Nie ma już problemów z indeksowaniem Z : portal pozwala na renderowanie
<body>
. Jeśli chcesz wyświetlić wyskakujące okienko lub menu rozwijane, jest to naprawdę fajny pomysł, jeśli nie chcesz walczyć z problemami z indeksem Z. Elementy portalu są dodawanedocument.body
w kolejności montowania, co oznacza, że o ile nie będziesz się nimi bawićz-index
, domyślnym zachowaniem będzie układanie portali jeden na drugim, w kolejności montowania. W praktyce oznacza to, że możesz bezpiecznie otworzyć wyskakujące okienko z innego wyskakującego okienka i upewnij się, że drugie wyskakujące okienko wyświetli się nad pierwszym, nawet o tym nie myślącz-index
.W praktyce
Najprościej: użyj lokalnego stanu React: jeśli uważasz, że w przypadku prostego wyskakującego okienka potwierdzenia usunięcia nie warto mieć płyty Redux, możesz skorzystać z portalu i znacznie upraszcza to kod. W przypadku takiego przypadku użycia, w którym interakcja jest bardzo lokalna i jest w rzeczywistości dość szczegółowa, czy naprawdę zależy ci na ponownym ładowaniu, podróżowaniu w czasie, rejestrowaniu akcji i wszystkich korzyściach, jakie przynosi Ci Redux? Osobiście nie używam w tym przypadku stanu lokalnego. Kod staje się tak prosty, jak:
Proste: nadal możesz używać stanu Redux : jeśli naprawdę chcesz, możesz nadal używać,
connect
aby wybrać, czy maDeleteConfirmationPopup
być pokazywany, czy nie. Ponieważ portal pozostaje głęboko zagnieżdżony w drzewie React, bardzo łatwo jest dostosować zachowanie tego portalu, ponieważ rodzic może przekazywać rekwizyty do portalu. Jeśli nie korzystasz z portali, zwykle musisz wyświetlać wyskakujące okienka na górze drzewa Reactz-index
powody, i zwykle musisz pomyśleć o takich rzeczach, jak „jak dostosować ogólny rodzaj DeleteConfirmationPopup, który zbudowałem zgodnie z przypadkiem użycia „. I zwykle znajdziesz dość hackerskie rozwiązania tego problemu, takie jak wysłanie akcji zawierającej zagnieżdżone akcje potwierdzenia / anulowania, klucz pakietu tłumaczeń lub, co gorsza, funkcja renderowania (lub coś innego, czego nie można zdiagnozować). Nie musisz tego robić z portalami i możesz po prostu przekazywać regularne rekwizyty, ponieważDeleteConfirmationPopup
jest to tylko dzieckoDeleteButton
Wniosek
Portale są bardzo przydatne w celu uproszczenia kodu. Nie poradzę sobie bez nich.
Pamiętaj, że implementacje portalu mogą również pomóc w innych przydatnych funkcjach, takich jak:
Reaktywuj portal lub Reaktywuj modalnie są przydatne w przypadku wyskakujących okienek, modów i nakładek, które powinny być pełnoekranowe, zwykle wyśrodkowane na środku ekranu.
Reakt-tether jest nieznany większości programistów React, ale jest to jedno z najbardziej przydatnych narzędzi, jakie można tam znaleźć. Tether pozwala tworzyć portale, ale automatycznie pozycjonuje portal względem danego celu. Jest to idealne rozwiązanie dla podpowiedzi, menu rozwijanych, hotspotów, skrzynek pomocy ... Jeśli kiedykolwiek miałeś problem z pozycją
absolute
/relative
iz-index
, lub gdy twoje menu rozwijane wykraczało poza obszar wyświetlania, Tether rozwiąże to wszystko za Ciebie.Możesz na przykład łatwo wdrożyć wbudowane hotspoty, które po kliknięciu zmieniają się w etykietkę:
Prawdziwy kod produkcyjny tutaj. Nie może być prostsze :)
Edycja : właśnie odkryłem bramkę reagującą, która pozwala renderować portale w wybranym węźle (niekoniecznie treści)
Edycja : wygląda na to, że reagujący popper może być przyzwoitą alternatywą dla tetheringu. PopperJS to biblioteka, która oblicza tylko odpowiednią pozycję dla elementu, nie dotykając bezpośrednio DOM, pozwalając użytkownikowi wybrać, gdzie i kiedy chce umieścić węzeł DOM, podczas gdy Tether dołącza się bezpośrednio do ciała.
Edycja : istnieje również możliwość wypełnienia szczeliny, która jest interesująca i może pomóc w rozwiązaniu podobnych problemów, umożliwiając renderowanie elementu w zarezerwowanym gnieździe elementu, który umieszczasz w dowolnym miejscu w drzewie
źródło
<Portal>
pochodzi? Zgaduję, że to portal reagujący, ale dobrze byłoby wiedzieć na pewno.Wiele dobrych rozwiązań i cennych komentarzy znanych ekspertów ze społeczności JS na ten temat można znaleźć tutaj. Może to wskazywać, że nie jest to tak trywialny problem, jak mogłoby się wydawać. Myślę, że właśnie dlatego może być źródłem wątpliwości i niepewności w tej kwestii.
Podstawowym problemem jest to, że w React możesz montować tylko komponenty do jego elementów nadrzędnych, co nie zawsze jest pożądanym zachowaniem. Ale jak rozwiązać ten problem?
Proponuję rozwiązanie, rozwiązane w celu rozwiązania tego problemu. Bardziej szczegółową definicję problemu, src i przykłady można znaleźć tutaj: https://github.com/fckt/react-layer-stack#rationale
Spójrz na https://github.com/fckt/react-layer-stack/blob/master/README.md#real-world-usage-example, aby zobaczyć konkretny przykład, który jest odpowiedzią na twoje pytanie:
źródło
Moim zdaniem absolutna minimalna implementacja ma dwa wymagania. Stan, który śledzi, czy modal jest otwarty, czy nie, oraz portal do renderowania modalu poza standardowym drzewem reakcji.
Składnik ModalContainer poniżej implementuje te wymagania wraz z odpowiednimi funkcjami renderowania dla modalu i wyzwalacza, który jest odpowiedzialny za wykonanie wywołania zwrotnego w celu otwarcia modalu.
A oto prosty przypadek użycia ...
Korzystam z funkcji renderowania, ponieważ chcę odizolować zarządzanie stanem i logikę podstawową od implementacji renderowanego modułu modalnego i wyzwalacza. Dzięki temu renderowane komponenty mogą być takie, jakie chcesz. W twoim przypadku przypuszczam, że komponent modalny może być połączonym komponentem, który odbiera funkcję zwrotną, która wywołuje akcję asynchroniczną.
Jeśli chcesz wysłać dynamiczne rekwizyty do komponentu modalnego z komponentu wyzwalającego, co, mam nadzieję, nie zdarza się zbyt często, polecam owijanie ModalContainer komponentem kontenerowym, który zarządza rekwizytami dynamicznymi we własnym stanie i ulepszenie oryginalnych metod renderowania, takich jak więc.
źródło
Zawiń modal w podłączony kontener i wykonaj tutaj operację asynchroniczną. W ten sposób możesz dotrzeć zarówno do wysyłki, aby wywołać akcje, jak i do prop onClose. Aby dosięgnąć
dispatch
rekwizytów, nie przekazujmapDispatchToProps
funkcji doconnect
.Aplikacja, w której moduł jest renderowany i ustawiony jest jego stan widoczności:
źródło