So synchronisieren Sie Redux-Status- und URL-Abfrageparameter


75

Ich habe eine Webseite mit einem Suchfeld. Das Suchfeld enthält mehrere Eingabefelder: ID, Größe, ...

Was ich möchte, ist, wenn der Benutzer Suchwerte festlegt (zum Beispiel: id = 123 und size = 45) und eine Suchtaste drückt:

  1. searchState im Redux-Reduzierer sollte mit neuen Suchwerten aktualisiert werden (id = 123 und size = 45).
  2. Die URL sollte in " http: // mydomain / home? Id = 123 & size = 45 " geändert werden.

Wenn der Benutzer die URL in http: // mydomain / home? Id = 111 & size = 22 ändert, gilt Folgendes :

  1. searchState im Reduzierer sollte mit neuen Suchwerten geändert werden (id = 111 und size = 22)
  2. Die Eingaben im UI-Suchfeld sollten mit neuen Werten aktualisiert werden (id = 111 und size = 22).

Wie mit Ziel erreichen? Welchen Router soll ich verwenden (React-Router, Redux-Router, React-Router-Redux oder andere)?

Antworten:


67

Ich würde vorschlagen , mit nur Router reagieren direkt und nicht zu halten searchStatein Redux. React Router fügt URL-Parameter in Ihre Komponenten ein, mit denen Sie mapStateToProps(state, ownProps)die endgültigen Requisiten berechnen können.

Wenn Sie Routenänderungen wirklich als Aktionen sehen möchten, können Sie React -Router-Redux für die bidirektionale Synchronisierung verwenden, aber es werden Ihnen nicht die Parameter im Status angezeigt - nur der aktuelle Speicherort. Der einzige Anwendungsfall dafür, wenn Sie Aktionen aufzeichnen und wiedergeben möchten und die URL-Leiste während der Wiedergabe aktualisieren soll.

Dies ist keinesfalls erforderlich. In den meisten Fällen reicht es aus, React Router direkt zu verwenden.


Hallo @Dan, wir stehen vor einem sehr ähnlichen Problem wie Anton. Ihre Antwort ist vielversprechend, aber es fällt uns schwer, ein gutes Beispiel zu finden, bei dem React Router oder sogar React Router in Kombination mit Redux den Status nur einer Komponente für mehrere verschiedene URLs ändert. In unserem Fall ändern wir das Hash-Tag und es sollte immer nur auf eine Komponente angewendet werden.
JoKer

1
Haben Sie eine einzige Route und verwenden Sie die Requisiten-Router-Injektionen, um diese Komponente zu steuern? Dies ist wirklich eine separate Frage, die nichts mit Redux zu tun hat, und Sie möchten sie möglicherweise separat stellen.
Dan Abramov

Ok, ich werde versuchen, eine neue Frage zu erstellen, in der ich mein Problem ausführlicher erkläre. Danke, dass du so schnell geantwortet hast.
JoKer

1
Hier ist meine neue Frage. Wäre echt schön wenn du mal reinschauen könntest. stackoverflow.com/questions/36722584/…
JoKer

Was ist mit der Verwendung von Routenparametern in Ihren Selektoren? scheint ein bisschen albern, dies von einer Komponente in den Selektor senden zu müssen, und mögliche Ursache für viele Duplikate
Benja

16

Kurz gesagt : Sie können Redux-Query-Sync verwenden , um die URL-Parameter und -Felder im Store synchron zu halten. Es funktioniert ohne Router.


Längere Geschichte : Als ich mit der gleichen Frage zu kämpfen hatte, schätzte ich zuerst Dan Abramovs Antwort und schlug vor, (in meinen Worten) die URL als 'zweiten Speicher' zu betrachten, einen Teil des Anwendungsstatus außerhalb des Redux-Speichers. Aber dann stellte ich fest, dass zwei Arten von "Geschäften" es schwierig machen, Code zu ändern, z. B. Dinge von einem zum anderen zu verschieben, da jedes "Geschäft" eine andere Oberfläche hat. Als Entwickler möchte ich lieber eines der Felder in meinem Redux Zustand auszuwählen, und entlarven sie in der URL, als ob der Ort ein kleines Fenster (eines Teils) waren mein Zustand.

Daher habe ich gerade redux-query-sync veröffentlicht, damit Sie eine Auswahlfunktion zum Auswählen eines Werts aus dem Status bereitstellen können, der dann an der Fensterposition unter einem von Ihnen angegebenen Parameternamen angezeigt wird. Damit es auch in die andere Richtung synchronisiert werden kann, also von der URL in den Redux-Status (z. B. beim ersten Laden der Anwendung), können Sie einen Aktionsersteller bereitstellen, dem der Parameterwert übergeben wird, damit Ihr Reduzierer den Status entsprechend aktualisieren kann.


2

So habe ich mit dem ersten Szenario umgegangen:

  • Wenn sich der Eingabewert ändert, löst seine Komponente einen Rückruf aus, der als Requisite aus seinem Container übergeben wurde.

  • Im Rückruf löst der Container die Aktion aus, die für die Aktualisierung des Redux-Status verantwortlich ist, wenn das Ereignis eintritt.

  • In der Zeile unmittelbar nach dem Aktionsaufruf verwende ich this.context.router.push()die URL mit der richtigen Abfragezeichenfolge und übergebe sie.

Ich bin mir nicht sicher, ob dies der richtige Ansatz ist. Ich fand es vorzuziehen, die URL zuerst zu aktualisieren, da die Abfragezeichenfolge meiner Meinung nach eher den Status als den Master widerspiegeln sollte.

In Bezug auf das umgekehrte Szenario bin ich mir wirklich nicht sicher. Es scheint, als würde das manuelle Festlegen der URL ein vollständiges Neuladen auslösen, aber ich könnte mich irren.

Für den zu verwendenden Router verwende ich den React Router selbst. Ich fand keinen wirklichen Wert darin, die anderen zu benutzen, und diese Diskussion war der Clou für mich.


Das Problem bei diesem Ansatz ist, wie ich sehe, dass, sobald Sie mehrere Komponenten im Container haben, die die URL ändern, es zu einem Durcheinander von Rückrufen und Aktualisierungen der URL-Parameter kommt.
Kann

2

Ich habe kürzlich die Arbeit an einem ähnlichen Thema beendet. Ich habe MobX als Store und Redux-Router als Router verwendet. (Ich habe mit dem React-Router gut abgeschnitten, aber ich musste eine Push-Aktion außerhalb der Komponente auslösen - Redux als globaler Store funktioniert hier hervorragend.)

Meine Lösung ähnelte der von cantera beschriebenen - mein Router-Status spiegelt lediglich den Formularstatus wider. Dies hat den zusätzlichen Vorteil, dass ich meinen Formularstatus nicht aufgeben muss und vollständig vom Router-Status abhängt.


Im ersten Szenario

1) Ich aktualisiere meine Formulareingabe wie gewohnt, wodurch ein erneutes Rendern in der Ergebniskomponente ausgelöst wird.

2) In componentDidUpdate()der Ergebniskomponente verwende ich die Formular-Requisiten, um die aktualisierte Abfragezeichenfolge zu erstellen.

3) Ich verschiebe die aktualisierte Abfragezeichenfolge in den Router-Status. Dies dient ausschließlich der Aktualisierung der URL.


Für das zweite Szenario

1) Im onEnterHook der Root- RouteKomponente erhalte ich die verfügbare Abfragezeichenfolge und analysiere sie in die ursprünglichen Formularwerte.

2) Ich aktualisiere meinen Shop mit den Werten. Dies gilt nur für das erste Laden der Seite und das einzige Mal, wenn der Router-Status den Formularstatus bestimmt.


Bearbeiten: Diese Lösung berücksichtigt nicht den Fall, wenn Sie in Ihren Browserverlauf zurückkehren, da die URL Ihren Status nicht aktualisiert.



2

Ich habe kürzlich die Arbeit an dieser Funktion für die App meines Unternehmens beendet. Wir wollten der URL verschiedene Suchanfragen hinzufügen.

Ein paar Dinge, die ich hier teilen möchte:

1) Wir haben Redux Store und React-Router verwendet. Da wir auch Typescript verwendet haben, haben wir letztendlich RouteComponentProps vom React-Router verwendet, um this.props.history.push () zum Aktualisieren der URL zu verwenden.

2) Wir haben alle Suchanfragen im Redux Store gespeichert. Der Workflow zum Aktualisieren des Redux-Speichers und anschließend der URL lautet wie folgt:

Wählen Sie in der App einige Filteroptionen aus => Versandaktionen, um den Filterstatus im Redux-Store zu aktualisieren => URL aktualisieren

3) Am Ende möchten wir auch, dass Benutzer eine URL mit Abfrageparametern eingeben können, die alle Filter in der App aktualisiert. Damit dies funktioniert, ist der Arbeitsablauf noch einfacher:

Der Benutzer gibt die URL => Versandaktionen ein, um den Redux-Status mit Abfrageparametern von der URL zu aktualisieren. Die Aktualisierung des Redux-Status führt automatisch zu einem erneuten Rendern in der App und alle Filter werden aktualisiert.

Das Wichtigste dabei ist also, den Redux-Status und die URL immer synchron zu halten.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.