Ich erstelle eine App, die in bestimmten Situationen einen Bestätigungsdialog anzeigen muss.
Angenommen, ich möchte etwas entfernen, dann werde ich eine Aktion wie diese deleteSomething(id)
auslösen, damit ein Reduzierer dieses Ereignis abfängt und den Dialogreduzierer ausfüllt, um es anzuzeigen.
Mein Zweifel kommt, wenn dieser Dialog eingereicht wird.
- Wie kann diese Komponente die richtige Aktion gemäß der ersten ausgelösten Aktion auslösen?
- Sollte der Aktionsersteller mit dieser Logik umgehen?
- Können wir Aktionen innerhalb des Reduzierers hinzufügen?
bearbeiten:
um es klarer zu machen:
deleteThingA(id) => show dialog with Questions => deleteThingARemotely(id)
createThingB(id) => Show dialog with Questions => createThingBRemotely(id)
Ich versuche also, die Dialogkomponente wiederzuverwenden. Das Ein- und Ausblenden des Dialogfelds ist nicht das Problem, da dies im Reduzierer leicht möglich ist. Ich versuche anzugeben, wie die Aktion von der rechten Seite entsprechend der Aktion versendet wird, die den Fluss auf der linken Seite startet.
javascript
modal-dialog
redux
react-redux
carlesba
quelle
quelle
Antworten:
Der Ansatz, den ich vorschlage, ist etwas ausführlich, aber ich fand, dass er sich ziemlich gut in komplexe Apps skalieren lässt. Wenn Sie ein Modal anzeigen möchten, lösen Sie eine Aktion aus, die beschreibt, welches Modal Sie sehen möchten :
Auslösen einer Aktion zum Anzeigen des Modals
(Strings können natürlich Konstanten sein; ich verwende der Einfachheit halber Inline-Strings.)
Schreiben eines Reduzierers zum Verwalten des Modalstatus
Stellen Sie dann sicher, dass Sie einen Reduzierer haben, der nur diese Werte akzeptiert:
Toll! Wenn Sie jetzt eine Aktion auslösen,
state.modal
wird diese aktualisiert und enthält nun Informationen zum aktuell sichtbaren modalen Fenster.Schreiben der Root-Modalkomponente
Fügen Sie im Stammverzeichnis Ihrer Komponentenhierarchie eine
<ModalRoot>
Komponente hinzu, die mit dem Redux-Speicher verbunden ist. Es wird zuhörenstate.modal
eine geeignete modale Komponente und anzeigen und die Requisiten von der weiterleitenstate.modal.modalProps
.Was haben wir hier gemacht?
ModalRoot
liest den aktuellenmodalType
undmodalProps
vonstate.modal
dem aus er verbunden ist, und rendert eine entsprechende Komponente wieDeletePostModal
oderConfirmLogoutModal
. Jedes Modal ist eine Komponente!Schreiben spezifischer modaler Komponenten
Hier gibt es keine allgemeinen Regeln. Sie sind nur React-Komponenten, die Aktionen auslösen, etwas aus dem Speicherstatus lesen können, auslösen und zufällig Modalitäten sein können .
Zum Beispiel
DeletePostModal
könnte es so aussehen:Das
DeletePostModal
ist mit dem Geschäft verbunden, sodass es den Post-Titel anzeigen kann und wie jede verbundene Komponente funktioniert: Es kann Aktionen auslösen, auchhideModal
wenn es notwendig ist, sich selbst zu verstecken.Extrahieren einer Präsentationskomponente
Es wäre umständlich, für jedes „spezifische“ Modal dieselbe Layoutlogik zu kopieren und einzufügen. Aber Sie haben Komponenten, richtig? So können Sie eine Präsentation extrahieren
<Modal>
, die nicht weiß, was bestimmte Modalitäten tun, aber wie sie aussehen.Dann können bestimmte Modalitäten, wie
DeletePostModal
sie zum Rendern verwendet werden können:Es liegt an Ihnen, eine Reihe von Requisiten zu entwickeln,
<Modal>
die in Ihrer Anwendung akzeptiert werden können, aber ich würde mir vorstellen, dass Sie verschiedene Arten von Modalitäten (z. B. Info-Modal, Bestätigungsmodal usw.) und verschiedene Stile für diese haben.Zugänglichkeit und Ausblenden bei Klicken außerhalb oder Escape-Taste
Der letzte wichtige Teil bei Modals ist, dass wir sie im Allgemeinen ausblenden möchten, wenn der Benutzer nach draußen klickt oder Escape drückt.
Anstatt Ihnen Ratschläge zur Implementierung zu geben, schlage ich vor, dass Sie es einfach nicht selbst implementieren. In Anbetracht der Zugänglichkeit ist es schwierig, das Richtige zu finden.
Stattdessen würde ich Ihnen empfehlen, eine zugängliche modale Standardkomponente wie z
react-modal
. Es ist vollständig anpassbar, Sie können alles hineinstecken, was Sie wollen, aber es handhabt die Zugänglichkeit korrekt, so dass Blinde Ihr Modal weiterhin verwenden können.Sie können sogar
react-modal
Ihre eigenen<Modal>
einbinden, die für Ihre Anwendungen spezifische Requisiten akzeptieren und untergeordnete Schaltflächen oder andere Inhalte generieren. Es sind alles nur Komponenten!Andere Ansätze
Es gibt mehr als einen Weg, dies zu tun.
Einige Leute mögen die Ausführlichkeit dieses Ansatzes nicht und bevorzugen eine
<Modal>
Komponente, die sie mit einer Technik namens „Portale“ direkt in ihren Komponenten rendern können . Mit Portalen können Sie eine Komponente in Ihrem rendern, während sie tatsächlich an einer vorbestimmten Stelle im DOM gerendert wird, was für Modale sehr praktisch ist.Tatsächlich habe
react-modal
ich das schon früher intern gemacht, so dass Sie es technisch nicht einmal von oben rendern müssen. Ich finde es immer noch schön, das Modal, das ich zeigen möchte, von der Komponente zu entkoppeln, die es zeigt, aber Sie können es auchreact-modal
direkt von Ihren Komponenten verwenden und das meiste, was ich oben geschrieben habe, überspringen.Ich ermutige Sie, beide Ansätze zu berücksichtigen, mit ihnen zu experimentieren und auszuwählen, was für Ihre App und Ihr Team am besten geeignet ist.
quelle
modalProps
auf die Aktion übergeben. Dies verstößt jedoch gegen die Regel, den Status serialisierbar zu halten. Wie kann ich dieses Problem lösen?Update : Reagiere 16.0 eingeführte Portale über
ReactDOM.createPortal
LinkUpdate : Die nächsten Versionen von React (Fibre: wahrscheinlich 16 oder 17) enthalten eine Methode zum Erstellen von Portalen:
ReactDOM.unstable_createPortal()
LinkVerwenden Sie Portale
Dan Abramov Antwort erster Teil ist in Ordnung, beinhaltet aber viel Boilerplate. Wie gesagt, Sie können auch Portale verwenden. Ich werde diese Idee etwas näher erläutern.
Der Vorteil eines Portals besteht darin, dass das Popup und die Schaltfläche mit der sehr einfachen Eltern-Kind-Kommunikation mithilfe von Requisiten sehr nahe am Reaktionsbaum bleiben: Sie können asynchrone Aktionen mit Portalen problemlos ausführen oder das Portal vom Elternteil anpassen lassen.
Was ist ein Portal?
Über ein Portal können Sie direkt in
document.body
einem Element rendern , das tief in Ihrem Reaktionsbaum verschachtelt ist.Die Idee ist, dass Sie beispielsweise den folgenden Reaktionsbaum in body rendern:
Und Sie erhalten als Ausgabe:
Der
inside-portal
Knoten wurde<body>
anstelle seiner normalen, tief verschachtelten Position im Inneren übersetzt .Wann man ein Portal benutzt
Ein Portal ist besonders hilfreich, um Elemente anzuzeigen, die über Ihre vorhandenen React-Komponenten hinausgehen sollen: Popups, Dropdowns, Vorschläge, Hotspots
Warum ein Portal benutzen?
Keine Z-Index-Probleme mehr : Über ein Portal können Sie rendern
<body>
. Wenn Sie ein Popup oder Dropdown anzeigen möchten, ist dies eine wirklich gute Idee, wenn Sie nicht gegen Z-Index-Probleme kämpfen müssen. Die hinzugefügten Portalelemente werdendocument.body
in der Mount-Reihenfolge hinzugefügt. Wenn Sie also nicht damit spielenz-index
, werden standardmäßig Portale in der Mount-Reihenfolge übereinander gestapelt. In der Praxis bedeutet dies, dass Sie ein Popup sicher aus einem anderen Popup heraus öffnen und sicherstellen können, dass das 2. Popup über dem ersten angezeigt wird, ohne darüber nachdenken zu müssenz-index
.In der Praxis
Am einfachsten: Verwenden Sie den lokalen Reaktionsstatus: Wenn Sie der Meinung sind, dass es für ein einfaches Popup zur Löschbestätigung nicht sinnvoll ist, das Redux-Boilerplate zu haben, können Sie ein Portal verwenden, das Ihren Code erheblich vereinfacht. Interessieren Sie sich in einem solchen Anwendungsfall, in dem die Interaktion sehr lokal ist und tatsächlich ein ziemliches Implementierungsdetail darstellt, wirklich für Hot-Reloading, Zeitreisen, Aktionsprotokollierung und alle Vorteile, die Redux Ihnen bietet? Persönlich tue ich das nicht und benutze in diesem Fall den lokalen Staat. Der Code wird so einfach wie:
Einfach: Sie können weiterhin den Redux-Status verwenden : Wenn Sie dies wirklich möchten, können Sie weiterhin
connect
auswählen, ob dasDeleteConfirmationPopup
angezeigt wird oder nicht. Da das Portal tief in Ihrem Reaktionsbaum verschachtelt bleibt, ist es sehr einfach, das Verhalten dieses Portals anzupassen, da Ihre Eltern Requisiten an das Portal übergeben können. Wenn Sie keine Portale verwenden, müssen Sie Ihre Popups normalerweise oben in Ihrem Reaktionsbaum für rendernz-index
Gründe und müssen in der Regel über Dinge wie "Wie passe ich das generische DeleteConfirmationPopup, das ich entsprechend dem Anwendungsfall erstellt habe" nachdenken. Und normalerweise finden Sie ziemlich hackige Lösungen für dieses Problem, z. B. das Versenden einer Aktion, die verschachtelte Bestätigungs- / Abbruchaktionen, einen Übersetzungspaketschlüssel oder noch schlimmer eine Renderfunktion (oder etwas anderes unserialisierbares) enthält. Sie müssen das nicht mit Portalen machen und können einfach normale Requisiten weitergeben, da diesDeleteConfirmationPopup
nur ein Kind der istDeleteButton
Fazit
Portale sind sehr nützlich, um Ihren Code zu vereinfachen. Ich konnte nicht mehr ohne sie auskommen.
Beachten Sie, dass Portalimplementierungen Ihnen auch bei anderen nützlichen Funktionen helfen können, wie z.
React -Portal oder React -Modal eignen sich gut für Popups, Modals und Overlays, die im Vollbildmodus angezeigt werden sollen und im Allgemeinen in der Mitte des Bildschirms zentriert sind.
React -Tether ist den meisten React-Entwicklern unbekannt, aber es ist eines der nützlichsten Tools, die Sie dort finden können. Mit Tether können Sie Portale erstellen, das Portal wird jedoch automatisch relativ zu einem bestimmten Ziel positioniert. Dies ist perfekt für Tooltips, Dropdowns, Hotspots, Helpboxes ... Wenn Sie jemals ein Problem mit Position
absolute
/relative
undz-index
hatten oder Ihr Dropdown außerhalb Ihres Ansichtsfensters liegt, wird Tether all das für Sie lösen.Sie können beispielsweise problemlos Onboarding-Hotspots implementieren, die nach dem Klicken zu einem Tooltip erweitert werden:
Echter Produktionscode hier. Einfacher geht es nicht :)
Bearbeiten : Gerade entdecktes React-Gateway, mit dem Portale in den Knoten Ihrer Wahl gerendert werden können (nicht unbedingt Body)
Bearbeiten : Es scheint, dass React-Popper eine anständige Alternative zu React-Tether sein kann. PopperJS ist eine Bibliothek, die nur eine geeignete Position für ein Element berechnet, ohne das DOM direkt zu berühren, sodass der Benutzer auswählen kann, wo und wann er den DOM-Knoten platzieren möchte, während Tether direkt an den Körper angehängt wird.
Bearbeiten : Es gibt auch React-Slot-Fill, was interessant ist und zur Lösung ähnlicher Probleme beitragen kann, indem ein Element in einen reservierten Element-Slot gerendert wird, den Sie an einer beliebigen Stelle in Ihrem Baum platzieren
quelle
<Portal>
? Ich vermute, es ist ein Reaktionsportal, aber es wäre schön, es sicher zu wissen.Viele gute Lösungen und wertvolle Kommentare bekannter Experten aus der JS-Community zu diesem Thema finden Sie hier. Es könnte ein Indikator dafür sein, dass es nicht so trivial ist, wie es scheint. Ich denke, dies könnte der Grund für Zweifel und Unsicherheit in dieser Frage sein.
Grundlegendes Problem hierbei ist, dass Sie in React nur Komponenten an deren übergeordneten Elementen mounten dürfen, was nicht immer das gewünschte Verhalten ist. Aber wie kann man dieses Problem angehen?
Ich schlage die Lösung vor, um dieses Problem zu beheben. Ausführlichere Problemdefinitionen, src und Beispiele finden Sie hier: https://github.com/fckt/react-layer-stack#rationale
Schauen Sie sich https://github.com/fckt/react-layer-stack/blob/master/README.md#real-world-usage-example an, um das konkrete Beispiel zu sehen, das die Antwort auf Ihre Frage ist:
quelle
Meiner Meinung nach hat die Mindestimplementierung zwei Anforderungen. Ein Status, der verfolgt, ob das Modal geöffnet ist oder nicht, und ein Portal, um das Modal außerhalb des Standardreaktionsbaums zu rendern.
Die folgende ModalContainer-Komponente implementiert diese Anforderungen zusammen mit den entsprechenden Renderfunktionen für das Modal und den Trigger, die für die Ausführung des Rückrufs zum Öffnen des Modals verantwortlich sind.
Und hier ist ein einfacher Anwendungsfall ...
Ich verwende Renderfunktionen, weil ich die Statusverwaltung und die Boilerplate-Logik von der Implementierung der gerenderten Modal- und Trigger-Komponente isolieren möchte. Auf diese Weise können die gerenderten Komponenten so sein, wie Sie es möchten. In Ihrem Fall könnte die modale Komponente eine verbundene Komponente sein, die eine Rückruffunktion empfängt, die eine asynchrone Aktion auslöst.
Wenn Sie dynamische Requisiten von der Trigger-Komponente an die Modalkomponente senden müssen, was hoffentlich nicht allzu oft vorkommt, empfehle ich, den ModalContainer mit einer Containerkomponente zu versehen, die die dynamischen Requisiten in ihrem eigenen Zustand verwaltet und die ursprünglichen Rendermethoden wie z so.
quelle
Wickeln Sie das Modal in einen verbundenen Container und führen Sie hier die asynchrone Operation aus. Auf diese Weise können Sie sowohl den Versand zum Auslösen von Aktionen als auch die onClose-Requisite erreichen. Erreichen
dispatch
von Requisiten, nicht nicht passierenmapDispatchToProps
Funktionconnect
.Die App, in der das Modal gerendert und sein Sichtbarkeitsstatus festgelegt wird:
quelle