Redux - mehrere Geschäfte, warum nicht?


220

Als Hinweis: Ich habe die Dokumente für Redux (auch Baobab) gelesen und einen angemessenen Anteil an Googeln und Testen durchgeführt.

Warum wird so dringend empfohlen, dass eine Redux-App nur einen Store hat?

Ich verstehe die Vor- und Nachteile eines Single-Store-Setups im Vergleich zu einem Multi-Store-Setup ( es gibt viele Fragen und Antworten zu SO zu diesem Thema ).

IMO, diese architektonische Entscheidung liegt bei den App-Entwicklern, basierend auf den Anforderungen ihrer Projekte. Warum wird es für Redux so dringend empfohlen, dass es fast obligatorisch klingt ( obwohl uns nichts davon abhält, mehrere Geschäfte zu eröffnen )?

BEARBEITEN: Feedback nach der Umstellung auf Single-Store

Nachdem ich einige Monate mit Redux an einem komplexen SPA gearbeitet habe, kann ich sagen, dass es eine Freude war, mit der Struktur eines einzelnen Geschäfts zu arbeiten.

Einige Punkte, die anderen helfen könnten zu verstehen, warum ein Geschäft im Vergleich zu vielen Geschäften in vielen, vielen Anwendungsfällen eine strittige Frage ist:

  • Es ist zuverlässig : Wir verwenden Selektoren, um den App-Status zu durchsuchen und kontextbezogene Informationen zu erhalten. Wir wissen, dass sich alle benötigten Daten in einem einzigen Geschäft befinden. Es werden alle Fragen vermieden, wo staatliche Probleme liegen könnten.
  • Es ist schnell : Unser Geschäft hat derzeit fast 100 Reduzierungen, wenn nicht mehr. Selbst bei dieser Zählung verarbeiten nur eine Handvoll Reduzierer Daten zu einem bestimmten Versand, die anderen geben nur den vorherigen Status zurück. Das Argument, dass ein riesiger / komplexer Laden ( Anzahl der Reduzierungen ) langsam ist, ist ziemlich umstritten. Zumindest haben wir von dort keine Leistungsprobleme gesehen.
  • Debugging-freundlich : Dies ist zwar ein überzeugendes Argument für die Verwendung von Redux als Ganzes, es gilt jedoch auch für einzelne Geschäfte im Vergleich zu mehreren Geschäften. Wenn Sie eine App erstellen, müssen Sie Statusfehler haben ( Programmiererfehler ). Dies ist normal. Bei der PITA dauert das Debuggen dieser Fehler Stunden. Dank des einzelnen Geschäfts ( und des Redux-Loggers ) haben wir nie mehr als ein paar Minuten mit einem bestimmten Statusproblem verbracht.

ein paar Hinweise

Die wahre Herausforderung beim Aufbau Ihres Redux-Geschäfts besteht darin, zu entscheiden, wie es strukturiert werden soll. Erstens, weil das Ändern der Struktur auf der Straße nur ein großer Schmerz ist. Zweitens, weil es weitgehend bestimmt, wie Sie Ihre App-Daten für einen beliebigen Prozess verwenden und abfragen. Es gibt viele Vorschläge zur Strukturierung eines Geschäfts. In unserem Fall fanden wir Folgendes ideal:

{
  apis: {     // data from various services
    api1: {},
    api2: {},
    ...
  }, 
  components: {} // UI state data for each widget, component, you name it 
  session: {} // session-specific information
}

Hoffentlich hilft dieses Feedback anderen.

EDIT 2 - hilfreiche Store-Tools

Für diejenigen unter Ihnen, die sich gefragt haben, wie sie ein einzelnes Geschäft "einfach" verwalten können, was schnell komplex werden kann. Es gibt Tools, mit denen Sie die strukturellen Abhängigkeiten / die Logik Ihres Geschäfts isolieren können.

Es gibt Normalizr, das Ihre Daten basierend auf einem Schema normalisiert. Es bietet dann eine Schnittstelle, über die Sie mit Ihren Daten arbeiten und andere Teile Ihrer Daten abrufen können id, ähnlich wie bei einem Wörterbuch.

Da ich Normalizr damals nicht kannte, baute ich etwas in die gleiche Richtung. relational-json verwendet ein Schema und gibt eine tabellenbasierte Schnittstelle zurück ( ähnlich einer Datenbank ). Der Vorteil von relational-json besteht darin, dass Ihre Datenstruktur dynamisch auf andere Teile Ihrer Daten verweist (im Wesentlichen können Sie Ihre Daten wie normale JS-Objekte in jede Richtung durchlaufen ). Es ist nicht so ausgereift wie Normalizr, aber ich verwende es seit einigen Monaten erfolgreich in der Produktion.


4
Ich mag Ihren Ansatz für die von Ihnen verwendete Geschäftsstruktur. Wie gehen Sie jedoch mit Änderungen des API-Status an, die Ihren Komponentenstatusänderungen zugeordnet sind? Angenommen, ich erhalte domänenspezifische Daten von meiner API. Wie führt dies zu einer generischen Datenstruktur, die in meinen Komponenten enthalten ist?
Diniden

Wie Ihre Komponenten Speicherdaten zuordnen / verwenden, liegt ganz bei Ihnen. Obwohl ich glaube, dass ich Ihre Frage nicht vollständig verstehe, können Sie eine Chat-Sitzung ausarbeiten oder starten?
Sebastien Daniel

2
Ich denke, die Frage wäre: Rendern Ihre Komponenten irgendwelche aus dem Apis-Status oder rendern sie nur das, was in den Komponentenstatus versetzt wird. Ich würde vermuten, wenn Sie es geschafft haben, NUR aus dem Status der Komponente zu rendern, haben Sie eine hervorragende Möglichkeit gefunden, Ihre Komponenten und Container auch bei Vorhandensein domänenspezifischer Daten wiederverwendbar zu machen. Wenn Ihre Komponenten teilweise aus dem API-Status UND dem Komponentenstatus gerendert werden, verwenden Sie vermutlich domänenspezifische Container, um die Daten in apis generischen Listen und Grundelementen zuzuordnen, die Ihre Komponenten verstehen.
Diniden

2
Ich verwende Redux in Verbindung mit Selektoren, bei denen es sich im Grunde genommen um funktional reine Datenmapper handelt. Jede Komponente "reagiert" auf das Speichern von Aktualisierungen. Wenn eine Änderung für sie relevant ist, "wählt" sie die Daten aus und rendert sie entsprechend. Also ja, Komponenten werden NUR basierend auf dem gerendert, was für sie wichtig ist. Das liegt aber nicht nur an Redux oder der Store-Struktur. Dies liegt an der Kombination eines unveränderlichen Datenspeichers, eines referenziellen Vergleichstests für Datenänderungen und eines reinen Selektors, der die von der Komponente benötigten Daten in dem von ihr benötigten Format abruft.
Sebastien Daniel

Hey @SebastienDaniel, können Sie ein Beispiel dafür zeigen, wie Sie die Überprüfung implementieren, die jede Komponente durchführt, um festzustellen, ob die Änderung im Store-Update für sie relevant ist? Ich meine, wenn Sie ein generisches Muster verwenden ... oder wenn Sie in jedem speziellen Fall prüfen, ob sich die spezifischen komponentenbezogenen Daten geändert haben.
John Bernardsson

Antworten:


232

Es gibt Randfälle, in denen Sie möglicherweise mehrere Speicher verwenden (z. B. wenn Sie Leistungsprobleme beim Aktualisieren von Listen mit Tausenden von Elementen haben, die mehrmals pro Sekunde gleichzeitig auf dem Bildschirm angezeigt werden). Das heißt, es ist eine Ausnahme und in den meisten Apps benötigen Sie nie mehr als einen einzelnen Store.

Warum betonen wir dies in den Dokumenten? Da die meisten Leute mit Flux-Hintergrund davon ausgehen, dass mehrere Stores die Lösung sind, um den Update-Code modular zu gestalten. Redux hat hierfür jedoch eine andere Lösung: die Reduziererzusammensetzung.

Wenn Sie mehrere Reduzierungen haben, die weiter in einen Reduzierungsbaum aufgeteilt sind, halten Sie Aktualisierungen in Redux modular. Wenn Sie dies nicht erkennen und sich für mehrere Geschäfte entscheiden, ohne vorher die Zusammensetzung des Reduzierers vollständig zu verstehen, werden Sie viele Vorteile der Redux-Architektur für einzelne Geschäfte verpassen:

  • Die Verwendung der Reduziererzusammensetzung erleichtert das Implementieren von "abhängigen Aktualisierungen" a la waitForin Flux, indem ein Reduzierer geschrieben wird, der andere Reduzierer manuell mit zusätzlichen Informationen und in einer bestimmten Reihenfolge aufruft.

  • Mit einem einzigen Geschäft ist es sehr einfach, den Zustand zu erhalten, zu hydrieren und zu lesen. Server-Rendering und Daten-Prefetching sind trivial, da nur ein Datenspeicher auf dem Client gefüllt und rehydriert werden muss und JSON seinen Inhalt beschreiben kann, ohne sich um die ID oder den Namen des Geschäfts kümmern zu müssen.

  • Ein einziges Geschäft ermöglicht Zeitreisefunktionen von Redux DevTools. Es macht auch Community-Erweiterungen wie Redux-Undo oder Redux-Optimist einfach, da sie auf der Reducer-Ebene arbeiten. Solche "Reducer Enhancer" können nicht für Geschäfte geschrieben werden.

  • Ein einziges Geschäft garantiert, dass die Abonnements erst nach Abwicklung des Versands aufgerufen werden. Das heißt, bis die Zuhörer benachrichtigt werden, wurde der Status vollständig aktualisiert. Bei vielen Geschäften gibt es keine solchen Garantien. Dies ist einer der Gründe, warum Flux die waitForKrücke braucht . Bei einem einzelnen Geschäft ist dies kein Problem, das Sie überhaupt sehen.

  • Vor allem sind in Redux mehrere Speicher nicht erforderlich (mit Ausnahme von Fällen mit Leistungsvorteilen, die Sie ohnehin zuerst profilieren sollten). Wir machen es zu einem wichtigen Punkt in den Dokumenten, damit Sie ermutigt werden, die Reduziererzusammensetzung und andere Redux-Muster zu lernen, anstatt Redux wie Flux zu verwenden und seine Vorteile zu verlieren.


11
Ich gebe zu, ich habe den vollen Vorteil / die Notwendigkeit der Reduziererzusammensetzung nicht verstanden. Dank Ihrer Antwort habe ich noch etwas gelesen und ein Beispiel (wieder TodoMVC). Mit einem so kleinen Beispiel war es schwer zu verstehen, welche tatsächliche Verbesserung die Reduziererzusammensetzung bietet. Mit ein wenig Nachdenken ist der Gewinn jedoch (jetzt) ​​im großen Maßstab offensichtlich. Nochmals vielen Dank, tolle Antwort!
Sebastien Daniel

4
@Sebastien Das Beispiel "Einkaufswagen" ist dafür besser, denke ich.
Dan Abramov

3
Ich implementiere Redux langsam in eine traditionelle (nicht SPA) Anwendung. Ich verwende Multilpe-Stores für jedes "Ganze", das ich in eine React / Redux-Implementierung konvertiere, bis die gesamte App so geändert werden kann, dass sie denselben Store verwendet.
Paul Knopf

5
@DanAbramov Neugierig, was Sie von einer Situation halten, in der Ihre Haupt- "App" einen eigenen Redux-Store ausführt und über npm eine eigenständige "App" importiert, die einen eigenen separaten Redux-Store betreibt. Wenn beispielsweise eines der anderen Teams in Ihrem Unternehmen über einen Messaging-Dienst mit einer Benutzeroberfläche verfügt, die Sie abrufen möchten, ohne Ihr Geschäft mit diesen Daten zu belasten.
Natlee75

6
@ natlee75 "Einige gültige Gründe für die Verwendung mehrerer Speicher in Redux können sein: [...] Isolieren einer Redux-App als Komponente in einer größeren Anwendung. In diesem Fall möchten Sie möglicherweise einen Speicher pro Stammkomponenteninstanz erstellen." Von redux.js.org/docs/FAQ.html#store-setup-multiple-stores
Kevin

24

In einigen sehr großen Unternehmensanwendungen mit Hunderten oder Tausenden von Reduzierungen ist es oft nützlich, sich verschiedene Bereiche der App als völlig separate Apps vorzustellen. In diesen Fällen (in denen es wirklich mehrere Apps sind, die einen Domainnamen gemeinsam haben) verwende ich mehrere Stores.

Zum Beispiel neige ich dazu, die folgenden allgemeinen Funktionsbereiche als separate Apps zu behandeln:

  • Administrator
  • Analytics / Daten in Dashboards
  • Abrechnungsmanagement und Einkaufsströme
  • Enterprise Account Team / Berechtigungsverwaltung

Wenn eines dieser Dinge klein ist, behalten Sie es einfach als Teil der Haupt-App. Wenn sie sehr groß werden (wie es einige Tools zur Verwaltung und Analyse von Unternehmenskonten tun), teilen Sie sie auf.

Der beste Weg, um sehr große Apps zu verwalten, besteht darin, sie wie eine Zusammensetzung vieler kleinerer Apps zu behandeln.

Wenn Ihre App weniger als 50.000 LOC beträgt, sollten Sie diesen Rat wahrscheinlich ignorieren und stattdessen Dans Rat befolgen.

Wenn Ihre App mehr als 1 Million LOC umfasst, sollten Sie wahrscheinlich Mini-Apps aufteilen, selbst wenn Sie sie in einem Mono-Repo verwalten.


5

Diese architektonische Entscheidung liegt bei den App-Entwicklern, basierend auf den Anforderungen ihrer Projekte

Du lebst in deiner eigenen Welt. Ich treffe mich mit Leuten, die Redux verwenden, weil es jeden Tag beliebt ist. Sie konnten sich nicht einmal vorstellen, wie viele Projekte ohne Entscheidung mit dem Reduzieren begonnen wurden. Ich hasse Redux-Ansätze, musste sie aber verwenden, weil andere Entwickler nichts anderes wissen. Es ist nur eine epische Blase, die von Facebook aufgeblasen wird.

  • Es ist nicht zuverlässig, da Teile des Geschäfts nicht isoliert sind.
  • Es ist ineffizient, weil Sie Hash-Versuche klonen und durchlaufen. Wenn Mutationen arithmetisch wachsen, wächst die Komplexität geometrisch. Sie konnten es nicht beheben, indem Sie Reduzierungen, Selektoren usw. umgestalteten. Sie müssen Ihren Versuch aufteilen.
  • Wenn es langsam wird , möchte niemand es in separate Anwendungen mit separaten Speichern aufteilen. Niemand möchte Geld für Refactoring ausgeben. Die Leute wandeln normalerweise einige intelligente Komponenten in Dump um und das war's. Wissen Sie, welche Zukunft auf Redux-Entwickler wartet? Sie werden diese Höllen aufrechterhalten.
  • Es ist nicht debugging-freundlich . Es ist schwierig, Verbindungen zwischen praktisch isolierten Teilen des Geschäfts zu debuggen. Es ist sehr schwierig, die Anzahl dieser Verbindungen zu analysieren.

Stellen wir uns vor, Sie haben mehrere Redux-Läden. Sie unterbrechen den unidirektionalen Datenfluss. Sie werden sofort feststellen, wie viele Verbindungen zwischen Geschäften Sie haben. Sie können unter diesen Verbindungen leiden, mit kreisförmigen Deps kämpfen usw.

Ein einziger unveränderlicher Speicher mit unidirektionalem Fluss ist nicht für jede Krankheit ein Elixier. Wenn Sie die Projektarchitektur nicht beibehalten möchten, leiden Sie trotzdem.


Mir hat gefallen, was Sie gesagt haben, und hier habe ich verwandte Fragen dazu gestellt. Würde es Ihnen etwas ausmachen, sich das anzuschauen, wenn Sie etwas Zeit haben und Ihre Meinungen teilen? Die Frage, die ich in Reddit gestellt habe, weil SO solche Fragen hier nicht fördert.
Arup Rakshit

3

In den folgenden Anwendungsfällen können mehrere Speicher hilfreich sein: 1. Wenn Sie große Komponenten haben, die hinsichtlich Datenstruktur, Verhalten und Anwendungskontext unabhängig voneinander sind. Durch das Isolieren dieser Komponenten können Sie Ihren Daten- und Anwendungsfluss einfacher verwalten. Es hilft auch bei der unabhängigen Entwicklung und Wartung Ihrer Komponenten. 2. Leistungsprobleme: Kein typischer Anwendungsfall. Wenn jedoch einige Ihrer Komponenten sehr häufig aktualisiert werden und keine Auswirkungen auf andere Komponenten haben, können Sie sich wahrscheinlich für andere Geschäfte entscheiden.

In allen anderen Fällen müssen Sie möglicherweise nicht mehrere Geschäfte haben. Wie Dan sagt, kann sich die Schaffung durchdachter Reduzierzusammensetzungen als bessere Lösung erweisen.


Ihre Nachricht sieht aus wie "Redux immer verwenden, außer in wenigen Fällen" == "Sie benötigen keine Projektarchitektur außer in wenigen Fällen". Es ist sehr realitätsnah, ich bin glücklich.
Puchu

2

Warum können wir nicht mehrere Speicher mit Redux verwenden?

Dies ist in Redux nicht erforderlich, da die Trennung zwischen Datendomänen bereits durch Aufteilen eines einzelnen Reduzierers in kleinere Reduzierer erreicht wird.


Kann oder sollte ich mehrere Geschäfte erstellen? Kann ich mein Geschäft direkt importieren und selbst in Komponenten verwenden?

Das ursprüngliche Flux-Muster beschreibt, dass eine App mehrere „Stores“ enthält, von denen jeder einen anderen Bereich von Domänendaten enthält. Dies kann zu Problemen führen, z. B. die Notwendigkeit, dass ein Geschäft auf ein anderes Geschäft wartet, um es zu aktualisieren.

Dies ist in Redux nicht erforderlich, da die Trennung zwischen Datendomänen bereits durch Aufteilen eines einzelnen Reduzierers in kleinere Reduzierer erreicht wird.

Wie bei mehreren anderen Fragen ist es möglich, mehrere unterschiedliche Redux-Speicher auf einer Seite zu erstellen, das beabsichtigte Muster besteht jedoch darin, nur einen einzigen Speicher zu haben. Ein einziger Speicher ermöglicht die Verwendung der Redux DevTools, vereinfacht das Speichern und Rehydrieren von Daten und vereinfacht die Abonnementlogik.

Einige gültige Gründe für die Verwendung mehrerer Geschäfte in Redux können sein:

Lösen eines Leistungsproblems, das durch zu häufige Aktualisierungen eines Teils des Status verursacht wird, wenn dies durch Profilierung der App bestätigt wird. Isolieren einer Redux-App als Komponente in einer größeren Anwendung. In diesem Fall möchten Sie möglicherweise einen Speicher pro Stammkomponenteninstanz erstellen. Das Erstellen neuer Geschäfte sollte jedoch nicht Ihr erster Instinkt sein, insbesondere wenn Sie aus einem Flux-Hintergrund stammen. Versuchen Sie zuerst die Zusammensetzung des Reduzierers und verwenden Sie nur dann mehrere Speicher, wenn dies Ihr Problem nicht löst.

Auch wenn Sie durch direktes Importieren auf Ihre Geschäftsinstanz verweisen können, ist dies in Redux kein empfohlenes Muster. Wenn Sie eine Geschäftsinstanz erstellen und aus einem Modul exportieren, wird sie zu einem Singleton. Dies bedeutet, dass es schwieriger ist, eine Redux-App als Komponente einer größeren App zu isolieren, falls dies jemals erforderlich sein sollte, oder das Server-Rendering zu aktivieren, da Sie auf dem Server für jede Anforderung separate Speicherinstanzen erstellen möchten.

offizielles Dokument von Redux


1

Ein Geschäft in Redux zu haben, ist in vielen Fällen wirklich das, was wir brauchen. Ich habe sowohl Redux als auch Flux verwendet und glaube, dass Redux die Arbeit besser macht!

Vergessen Sie nicht, dass sich der Speicher in einem JavaScript-Objekt befindet. Obwohl Sie nur einen Speicher haben, kann er leicht erweitert und wiederverwendet werden. Für mich erleichtert ein Speicher das Durchlaufen mit Redux-Entwicklungstools erheblich und lässt sich nicht verwechseln große Anwendungen ...

Auch das Konzept eines Geschäfts ahmt für uns die Datenbank nach, eine Quelle der Wahrheit, die Sie ändern und im Browser-Speicher darauf zugreifen können ...

Wenn die gesamte Anwendung gut verwaltet wird, kann ein Geschäft ausreichen, um den gesamten Anwendungsstatus zu verwalten ...


3
Daher sollte jeder glauben, dass ein einzelnes Geschäft seine Arbeit besser macht und niemand erklären kann, warum. Es erinnert mich etwas ...
Puchu
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.