In einer Flux-App sollte es nur einen Dispatcher geben. Alle Daten fließen über diesen zentralen Hub. Mit einem Singleton-Dispatcher können alle Stores verwaltet werden. Dies ist wichtig, wenn Sie Store # 1 selbst aktualisieren müssen und Store # 2 sich dann selbst basierend auf der Aktion und dem Status von Store # 1 aktualisieren muss. Flux geht davon aus, dass diese Situation in einer großen Anwendung möglich ist. Im Idealfall muss diese Situation nicht eintreten, und Entwickler sollten sich bemühen, diese Komplexität nach Möglichkeit zu vermeiden. Aber der Singleton Dispatcher ist bereit, es zu handhaben, wenn es soweit ist.
Geschäfte sind auch Singletons. Sie sollten so unabhängig und entkoppelt wie möglich bleiben - ein in sich geschlossenes Universum, das man aus einer Controller-Ansicht abfragen kann. Der einzige Weg in den Store führt über den Rückruf, den er beim Dispatcher registriert. Der einzige Ausweg führt über Getter-Funktionen. Stores veröffentlichen auch ein Ereignis, wenn sich ihr Status geändert hat, sodass Controller-Views mithilfe der Getter wissen können, wann sie nach dem neuen Status fragen müssen.
In Ihrer Beispiel-App würde es eine einzige geben PostStore
. Derselbe Speicher könnte die Beiträge auf einer "Seite" (Pseudoseite) verwalten, die eher dem Newsfeed von FB ähnelt, in dem Beiträge von verschiedenen Benutzern angezeigt werden. Seine logische Domäne ist die Liste der Beiträge, und er kann jede Liste von Beiträgen verarbeiten. Wenn wir von Pseudoseite zu Pseudoseite wechseln, möchten wir den Status des Geschäfts neu initialisieren, um den neuen Status widerzuspiegeln. Möglicherweise möchten wir auch den vorherigen Status in localStorage als Optimierung für das Hin- und Herwechseln zwischen Pseudoseiten zwischenspeichern, aber meine Neigung wäre, eine einzurichten, PageStore
die auf alle anderen Geschäfte wartet und die Beziehung zu localStorage für alle Geschäfte verwaltet die Pseudoseite und aktualisiert dann ihren eigenen Status. Beachten Sie, dass dies PageStore
nichts über die Beiträge speichern würde - das ist die Domäne derPostStore
. Es würde einfach wissen, ob eine bestimmte Pseudoseite zwischengespeichert wurde oder nicht, weil Pseudoseiten ihre Domäne sind.
Das PostStore
hätte eine initialize()
Methode. Diese Methode löscht immer den alten Status, auch wenn dies die erste Initialisierung ist, und erstellt dann den Status basierend auf den Daten, die über die Aktion über den Dispatcher empfangen wurden. Das Verschieben von einer Pseudoseite zu einer anderen würde wahrscheinlich eine PAGE_UPDATE
Aktion beinhalten, die den Aufruf von auslösen würde initialize()
. Es gibt Details zum Abrufen von Daten aus dem lokalen Cache, zum Abrufen von Daten vom Server, zum optimistischen Rendern und zu XHR-Fehlerzuständen. Dies ist jedoch die allgemeine Idee.
Wenn eine bestimmte Pseudoseite nicht alle Speicher in der Anwendung benötigt, bin ich mir nicht ganz sicher, ob es einen Grund gibt, die nicht verwendeten zu zerstören, außer Speicherbeschränkungen. Geschäfte verbrauchen jedoch normalerweise nicht viel Speicher. Sie müssen nur sicherstellen, dass die Ereignis-Listener in den Controller-Ansichten, die Sie zerstören, entfernt werden. Dies geschieht nach der componentWillUnmount()
Methode von React .
UserListStore
mit allen relevanten Benutzern. Und jeder Benutzer hätte ein paar boolesche Flags, die die Beziehung zum aktuellen Benutzerprofil beschreiben. So etwas{ follower: true, followed: false }
zum Beispiel. Die MethodengetFolloweds()
undgetFollowers()
würden die verschiedenen Benutzergruppen abrufen, die Sie für die Benutzeroberfläche benötigen.(Hinweis: Ich habe die ES6-Syntax mit der Option JSX Harmony verwendet.)
Als Übung habe ich eine Beispiel-Flux-App geschrieben , die das Durchsuchen
Github users
und Repos ermöglicht.Es basiert auf der Antwort von Fisherwebdev , spiegelt aber auch einen Ansatz wider, den ich zur Normalisierung von API-Antworten verwende.
Ich habe es geschafft, einige Ansätze zu dokumentieren, die ich beim Erlernen von Flux ausprobiert habe.
Ich habe versucht, es nahe an der realen Welt zu halten (Paginierung, keine gefälschten localStorage-APIs).
Hier sind einige Punkte, die mich besonders interessiert haben:
switch
mit Aktionen enthalten .Wie ich Geschäfte klassifiziere
Ich habe versucht, einige der Duplikate zu vermeiden, die ich in anderen Flux-Beispielen gesehen habe, insbesondere in Stores. Ich fand es nützlich, Stores logisch in drei Kategorien zu unterteilen:
Inhaltsspeicher enthalten alle App-Entitäten. Alles, was eine ID hat, benötigt einen eigenen Content Store. Komponenten, die einzelne Elemente rendern, fragen Content Stores nach den neuen Daten.
Inhaltsspeicher sammeln ihre Objekte aus allen Serveraktionen. Zum Beispiel
UserStore
untersuchtaction.response.entities.users
, wenn es vorhanden ist, unabhängig davon Aktion gefeuert. Es besteht keine Notwendigkeit für eineswitch
. Normalizr macht es einfach, API-Antworten auf dieses Format zu reduzieren.Listenspeicher verfolgen die IDs von Entitäten, die in einer globalen Liste angezeigt werden (z. B. "Feed", "Ihre Benachrichtigungen"). In diesem Projekt habe ich keine solchen Geschäfte, aber ich dachte, ich würde sie trotzdem erwähnen. Sie behandeln die Paginierung.
Sie reagieren normalerweise auf wenige Aktionen (zB
REQUEST_FEED
,REQUEST_FEED_SUCCESS
,REQUEST_FEED_ERROR
).Indizierte Listenspeicher sind wie Listenspeicher, definieren jedoch eine Eins-zu-Viele-Beziehung. Zum Beispiel "Abonnenten des Benutzers", "Sterngucker des Repositorys", "Repositorys des Benutzers". Sie behandeln auch die Paginierung.
Sie reagieren auch normalerweise nur ein paar Aktionen (zB
REQUEST_USER_REPOS
,REQUEST_USER_REPOS_SUCCESS
,REQUEST_USER_REPOS_ERROR
).In den meisten sozialen Apps gibt es viele davon, und Sie möchten schnell eine weitere erstellen können.
Hinweis: Dies sind keine tatsächlichen Klassen oder ähnliches. So denke ich gerne über Geschäfte nach. Ich habe allerdings ein paar Helfer gemacht.
StoreUtils
createStore
Diese Methode bietet Ihnen den grundlegendsten Store:
Ich benutze es, um alle Stores zu erstellen.
isInBag
,mergeIntoBag
Kleine Helfer für Content Stores.
PaginatedList
Speichert den Paginierungsstatus und erzwingt bestimmte Zusicherungen (beim Abrufen können keine Seiten abgerufen werden usw.).
PaginatedStoreUtils
createListStore
,createIndexedListStore
,createListActionHandler
Vereinfacht die Erstellung indizierter Listenspeicher so einfach wie möglich, indem Boilerplate-Methoden und die Handhabung von Aktionen bereitgestellt werden:
createStoreMixin
Ein Mixin, mit dem Komponenten auf Stores zugreifen können, an denen sie interessiert sind, z
mixins: [createStoreMixin(UserStore)]
.quelle
In Reflux wird das Konzept des Dispatchers entfernt und Sie müssen nur noch an den Datenfluss durch Aktionen und Speicher denken. Dh
Jeder Pfeil hier modelliert, wie der Datenfluss abgehört wird, was wiederum bedeutet, dass die Daten in die entgegengesetzte Richtung fließen. Die tatsächliche Zahl für den Datenfluss lautet wie folgt:
In Ihrem Anwendungsfall benötigen wir, wenn ich das richtig verstanden habe, eine
openUserProfile
Aktion, die das Laden und Wechseln des Benutzerprofils initiiert, sowie einige Aktionen zum Laden von Posts, die Posts laden, wenn die Benutzerprofilseite geöffnet wird und während des unendlichen Bildlaufereignisses. Ich würde mir also vorstellen, dass die Anwendung die folgenden Datenspeicher enthält:In Reflux würden Sie es so einrichten:
Die Taten
Der Seitenspeicher
Der Benutzerprofilspeicher
Die Beiträge speichern
Die Komponenten
Ich gehe davon aus, dass Sie eine Komponente für die gesamte Seitenansicht, die Benutzerprofilseite und die Liste der Beiträge haben. Folgendes muss verkabelt werden:
Action.openUserProfile
mit der richtigen ID während des Klickereignisses aufrufen .currentPageStore
damit sie weiß, zu welcher Seite sie wechseln soll.currentUserProfileStore
damit sie weiß, welche Benutzerprofildaten angezeigt werden sollencurrentPostsStore
, um die geladenen Beiträge zu erhaltenAction.loadMorePosts
.Und das sollte so ziemlich alles sein.
quelle