So synchronisieren Sie Redux-Status- und URL-Hash-Tag-Parameter

76

Wir haben eine Liste von Vorlesungen und Kapiteln, in denen der Benutzer sie auswählen und abwählen kann. Die beiden Listen werden in einem Redux-Speicher gespeichert. Jetzt möchten wir eine Darstellung ausgewählter Vorlesungs- und Kapitel-Slugs im Hash-Tag der URL behalten, und alle Änderungen an der URL sollten auch den Speicher ändern (bidirektionale Synchronisierung).

Was wäre die beste Lösung mit React-Router oder sogar React-Router-Redux ?

Wir konnten nicht wirklich einige gute Beispiele finden, bei denen der Reaktionsrouter nur zum Verwalten des Hash-Tags einer URL verwendet wird und auch nur eine Komponente aktualisiert.

Joker
quelle
4
Warum möchten Sie diesen Status im Store beibehalten, anstatt nur React Router als Quelle der Wahrheit für URL-Parameter zu verwenden und die Requisiten zu verwenden, die in Ihre mapStateToProps (state, ownProps) eingefügt werden?
Dan Abramov
2
Weil die URL-Parameter nur die Slugs der Vorlesungen und der ausgewählten Kapitel enthalten. Im Laden habe ich eine Liste von Vorlesungen und Kapiteln mit einem Namen, einer Schnecke und einem ausgewählten Booleschen Wert.
JoKer

Antworten:

149

Ich denke du musst nicht.
(Entschuldigen Sie eine abweisende Antwort, aber meiner Erfahrung nach ist dies die beste Lösung.)

Der Speicher ist die Quelle der Wahrheit für Ihre Daten. Das ist in Ordnung.
Wenn Sie React Router verwenden, lassen Sie es die Quelle der Wahrheit für Ihren URL-Status sein.
Sie müssen nicht alles im Laden behalten.

Betrachten Sie zum Beispiel Ihren Anwendungsfall:

Weil die URL-Parameter nur die Slugs der Vorlesungen und der ausgewählten Kapitel enthalten. Im Laden habe ich eine Liste von Vorlesungen und Kapiteln mit einem Namen, einer Schnecke und einem ausgewählten Booleschen Wert.

Das Problem ist, dass Sie die Daten duplizieren. Die Daten in store ( chapter.selected) werden im React Router-Status dupliziert. Eine Lösung wäre, sie zu synchronisieren, aber dies wird schnell komplex. Warum nicht einfach React Router die Quelle der Wahrheit für ausgewählte Kapitel sein lassen?

Ihr Geschäftsstatus würde dann wie folgt aussehen (vereinfacht):

{
  // Might be paginated, kept inside a "book", etc:
  visibleChapterSlugs: ['intro', 'wow', 'ending'],

  // A simple ID dictionary:
  chaptersBySlug: {
    'intro': {
      slug: 'intro',
      title: 'Introduction'
    },
    'wow': {
      slug: 'wow',
      title: 'All the things'
    },
    'ending': {
      slug: 'ending',
      title: 'The End!'
    }
  }
}

Das ist es! Nicht selecteddort aufbewahren. Lassen Sie stattdessen React Router damit umgehen. Schreiben Sie in Ihren Routen-Handler so etwas wie

function ChapterList({ chapters }) {
  return (
    <div>
      {chapters.map(chapter => <Chapter chapter={chapter} key={chapter.slug} />)}
    </div>
  )
}

const mapStateToProps = (state, ownProps) => {
  // Use props injected by React Router:
  const selectedSlugs = ownProps.params.selectedSlugs.split(';')

  // Use both state and this information to generate final props:
  const chapters = state.visibleChapterSlugs.map(slug => {
    return Object.assign({
      isSelected: selectedSlugs.indexOf(slug) > -1,
    }, state.chaptersBySlug[slug])
  })

  return { chapters }
}

export default connect(mapStateToProps)(ChapterList)
Dan Abramov
quelle
4
Es tut mir leid, dass ich so spät zurückgekommen bin, aber ich war letzte Woche im Urlaub. Ich habe eine Frage. Sie haben eine Möglichkeit beschrieben, die Daten aus der URL abzurufen und zu rendern. Wie würden Sie die URL mit den neu ausgewählten Kapiteln aktualisieren?
JoKer
9
Ich würde den Aktionsersteller aufrufen browserHistory.push()(woher browserHistorywird er importiert react-router). Ich würde wahrscheinlich Redux Thunk verwenden, um klar zu machen, dass es einen Nebeneffekt gibt. Ich würde dispatch({ ... }); browserHistory.push(...)drinnen anrufen .
Dan Abramov
2
Hey Dan. Danke für Redux! Ich habe auch meine 2 Cent in das Thema gesteckt und eine Frage gestellt. Was ist, wenn eine Logik zum Übergang des Anwendungsstatus von den Daten in einer Abfrage abhängt? Das heißt, die Reduzierer brauchen es und Sie können es nicht einfach im Laden loswerden.
Alexander Reshytko
2
@AlexanderReshytko Da diese Daten aus der „Außenwelt“ stammen, würde ich bei Bedarf Aktionen damit ausführen . Dies bedeutet jedoch nicht, dass Sie eine generische Aktion "Route geändert" benötigen (obwohl Sie sie versenden können, wenn Sie sie nützlich finden). Ihre Reduzierer könnten diese Informationen dann wie gewohnt verwenden.
Dan Abramov
8
Es ist etwas umständlich, Parameter an die Auswahl von Selektoren zu senden. Daher ist es sehr nützlich, die aktuellen URL-Parameter aus dem Store abzurufen.
Jacob Rask
3

react-router-redux kann Ihnen helfen, das zu speichernde URL-Material einzufügen. Speichern Sie es also jedes Mal, wenn sich das Hash-Tag ändert.

David Guan
quelle
23
Es gibt Ihnen nur den Speicherort und nicht die analysierten Parameter. Daher ist es nur von begrenztem Nutzen, es sei denn, Sie können das, was React Router Ihnen manuell bietet, erneut implementieren. Es ist eine gute Lösung, um den Speicher mit Aktionen synchron zu halten, damit das Aufzeichnen und Wiedergeben von Benutzersitzungen funktioniert, aber für Apps, die dies nicht benötigen, ist es nicht wirklich nützlich.
Dan Abramov