Ich benutze Redux für das State Management.
Wie setze ich den Speicher in den Ausgangszustand zurück?
Angenommen, ich habe zwei Benutzerkonten ( u1
und u2
).
Stellen Sie sich die folgende Abfolge von Ereignissen vor:
Der Benutzer
u1
meldet sich bei der App an und unternimmt etwas, sodass wir einige Daten im Store zwischenspeichern.Benutzer
u1
meldet sich ab.Der Benutzer
u2
meldet sich bei der App an, ohne den Browser zu aktualisieren.
Zu diesem Zeitpunkt werden die zwischengespeicherten Daten verknüpft u1
, und ich möchte sie bereinigen.
Wie kann ich den Redux-Speicher auf den Ausgangszustand zurücksetzen, wenn sich der erste Benutzer abmeldet?
Antworten:
Eine Möglichkeit, dies zu tun, besteht darin, einen Root-Reduzierer in Ihre Anwendung zu schreiben.
Der Root-Reduzierer delegiert normalerweise die Verarbeitung der Aktion an den Reduzierer, der von generiert wird
combineReducers()
. Wenn jedoch eineUSER_LOGOUT
Aktion empfangen wird , wird der Ausgangszustand erneut zurückgegeben.Wenn Ihr Root-Reducer beispielsweise so aussah:
Sie können es umbenennen
appReducer
und eine neuerootReducer
Delegierung darauf schreiben :Jetzt müssen wir nur noch das Neue lehren
rootReducer
, um nach derUSER_LOGOUT
Aktion den Ausgangszustand wiederherzustellen. Wie wir wissen, sollen Reduzierer den Ausgangszustand zurückgeben, wenn sieundefined
als erstes Argument aufgerufen werden , unabhängig von der Aktion. Verwendenstate
wir diese Tatsache, um das Akkumulierte unter bestimmten Bedingungen zu entfernenappReducer
:Jetzt werden bei jedem
USER_LOGOUT
Brand alle Reduzierungen neu initialisiert. Sie können auch etwas anderes zurückgeben als ursprünglich, wenn sie möchten, da sie dies auch überprüfen könnenaction.type
.Um es noch einmal zu wiederholen: Der vollständige neue Code sieht folgendermaßen aus:
Beachten Sie, dass ich den Status hier nicht mutiere, sondern lediglich die Referenz einer aufgerufenen lokalen Variablen neu zuweise,
state
bevor ich sie an eine andere Funktion übergebe. Das Mutieren eines Zustandsobjekts wäre ein Verstoß gegen die Redux-Prinzipien.Wenn Sie Redux-Persist verwenden , müssen Sie möglicherweise auch Ihren Speicher reinigen. Redux-persist speichert eine Kopie Ihres Status in einer Speicher-Engine, und die Statuskopie wird bei der Aktualisierung von dort geladen.
Zuerst müssen Sie die entsprechende Speicher-Engine importieren und dann den Status analysieren, bevor Sie ihn festlegen
undefined
und jeden Speicherstatus-Schlüssel bereinigen.quelle
case 'CLEAR_DATA': return initialState
export const createRootReducer = asyncReducers => { const appReducer = combineReducers({ myReducer ...asyncReducers }); return (state, action) => { if (action.type === 'LOGOUT_USER') { state = undefined; } return appReducer(state, action); } };
if (action.type === 'RESET') return action.stateFromLocalStorage
USER_LOGOUT
, ist es nach dem Auslösen der Aktion möglich, Statusdaten von früher zu erhalten? (zB über Devtools)Ich möchte darauf hinweisen, dass der akzeptierte Kommentar von Dan Abramov korrekt ist, außer dass bei der Verwendung des React-Router-Redux-Pakets zusammen mit diesem Ansatz ein seltsames Problem aufgetreten ist. Unser Fix bestand darin, den Status nicht auf
undefined
den aktuellen Routing-Reduzierer zu setzen, sondern diesen weiterhin zu verwenden. Daher würde ich vorschlagen, die folgende Lösung zu implementieren, wenn Sie dieses Paket verwendenquelle
router
rounting
combineReducers()
..... wenn SiecombineReducers({routing: routingReducer})
es hätten, wäre es wie in der Antwort beschriebenAktion definieren:
Dann in jedem Ihrer Reduzierer unter der Annahme, dass Sie mehrere Aktionen durch jeden Reduzierer verwenden
switch
oderif-else
ausführen. Ich werde den Fall für eine nehmenswitch
.Auf diese Weise
RESET
aktualisiert Ihr Reduzierer den Speicher bei jedem Aufruf von action mit dem Standardstatus.Zum Abmelden können Sie jetzt Folgendes tun:
Jedes Mal, wenn sich ein Benutzer anmeldet, ohne dass ein Browser aktualisiert wird. Der Speicher ist immer standardmäßig aktiviert.
store.dispatch(RESET_ACTION)
arbeitet nur die Idee aus. Sie werden höchstwahrscheinlich einen Aktionsersteller für diesen Zweck haben. Ein viel besserer Weg wird sein, dass Sie eine habenLOGOUT_ACTION
.Sobald Sie dies versenden
LOGOUT_ACTION
. Eine benutzerdefinierte Middleware kann diese Aktion dann entweder mit Redux-Saga oder Redux-Thunk abfangen. In beiden Fällen können Sie jedoch eine andere Aktion 'RESET' auslösen. Auf diese Weise erfolgt das Abmelden und Zurücksetzen des Geschäfts synchron und Ihr Geschäft ist für die Anmeldung eines anderen Benutzers bereit.quelle
undefined
dass er in der anderen Antwort gefällt. Wenn Ihre Anwendung einen Statusbaum erwartet und Sie ihnundefined
stattdessen angeben, müssen nur mehr Fehler und Kopfschmerzen behoben werden als nur ein leerer Baum.Nur eine vereinfachte Antwort auf die beste Antwort:
quelle
Sie können auch eine Aktion auslösen, die von allen oder einigen Reduzierern ausgeführt wird und die Sie auf den ursprünglichen Speicher zurücksetzen möchten. Eine Aktion kann einen Reset auf Ihren gesamten Status auslösen oder nur einen Teil davon, der Ihnen passend erscheint. Ich glaube, dies ist der einfachste und kontrollierbarste Weg, dies zu tun.
quelle
Wenn Sie mit Redux die folgende Lösung angewendet haben, wird davon ausgegangen, dass ich in allen meinen Reduzierungen einen initialState festgelegt habe (z. B. {user: {name, email}}). In vielen Komponenten überprüfe ich diese verschachtelten Eigenschaften, sodass ich mit diesem Fix verhindere, dass meine Rendermethoden unter gekoppelten Eigenschaftsbedingungen beschädigt werden (z. B. wenn state.user.email, das einen Fehler auslöst, undefiniert ist, wenn oben genannte Lösungen verwendet werden).
quelle
UPDATE NGRX4
Wenn Sie auf NGRX 4 migrieren, haben Sie möglicherweise aus dem Migrationshandbuch festgestellt , dass die Rootreducer-Methode zum Kombinieren Ihrer Reduzierer durch die ActionReducerMap-Methode ersetzt wurde. Diese neue Vorgehensweise könnte das Zurücksetzen des Status zunächst zu einer Herausforderung machen. Es ist eigentlich unkompliziert, aber die Art und Weise, dies zu tun, hat sich geändert.
Diese Lösung ist vom Meta- Reducer -API-Abschnitt der NGRX4 Github-Dokumente inspiriert .
Nehmen wir zunächst an, Sie kombinieren Ihre Reduzierungen wie folgt mit der neuen ActionReducerMap-Option von NGRX:
Angenommen, Sie möchten den Status in app.module `zurücksetzen
`
Und das ist im Grunde eine Möglichkeit, mit NGRX 4 den gleichen Effekt zu erzielen.
quelle
router
Ich kombinierte die Ansätze von Dan, Ryan und Rob, um den Zustand beizubehalten und alles andere im Staatsbaum zu initialisieren, und kam zu folgendem Ergebnis:quelle
Ich habe eine Komponente erstellt, mit der Redux den Status zurücksetzen kann. Sie müssen diese Komponente nur verwenden, um Ihr Geschäft zu erweitern und einen bestimmten action.type auszulösen, um das Zurücksetzen auszulösen. Der Gedanke an die Implementierung ist der gleiche wie der von @Dan Abramov.
Github: https://github.com/wwayne/redux-reset
quelle
Ich habe Aktionen erstellt, um den Status zu löschen. Wenn ich also einen Ersteller einer Abmeldeaktion versende, versende ich auch Aktionen, um den Status zu löschen.
Benutzerdatensatzaktion
Abmeldeaktionsersteller
Reduzierstück
Ich bin mir nicht sicher, ob dies optimal ist?
quelle
Wenn Sie Redux-Aktionen verwenden , finden Sie hier eine schnelle Problemumgehung mit einem HOF ( Higher Order Function ) für
handleActions
.Und dann
handleActionsEx
anstelle von Original verwendenhandleActions
, um Reduzierstücke zu handhaben.Dans Antwort gibt eine großartige Vorstellung von diesem Problem, aber es hat für mich nicht gut geklappt, weil ich es benutze
redux-persist
.Bei Verwendung mit
redux-persist
löste das einfache Übergeben desundefined
Status kein anhaltendes Verhalten aus, sodass ich wusste, dass ich das Element manuell aus dem Speicher entfernen musste (in meinem Fall also React NativeAsyncStorage
).oder
hat auch bei mir nicht funktioniert - sie haben mich nur angeschrien. (zB Beschwerden wie "Unerwarteter Schlüssel _persist ..." )
Dann dachte ich plötzlich darüber nach, dass ich nur möchte, dass jeder einzelne Reduzierer seinen eigenen Ausgangszustand zurückgibt, wenn ein
RESET
Aktionstyp auftritt. Auf diese Weise wird das Fortbestehen auf natürliche Weise gehandhabt. Ohne die oben genannte Utility-Funktion (handleActionsEx
) sieht mein Code natürlich nicht trocken aus (obwohl es nur einRESET: () => initialState
Einzeiler ist , dh ), aber ich konnte es nicht ertragen, weil ich die Metaprogrammierung liebe.quelle
Die folgende Lösung hat bei mir funktioniert.
Ich habe Meta-Reduzierern die Funktion zum Zurücksetzen des Status hinzugefügt. Der Schlüssel war zu verwenden
um alle Reduzierstücke in den Ausgangszustand zu versetzen. Die Rückgabe
undefined
verursachte Fehler, da die Struktur des Geschäfts zerstört wurde./reducers/index.ts
app.module.ts
quelle
Aus Sicht der Sicherheit zu tun , die sicherste Sache , wenn ein Benutzer aus der Anmeldung ist es, alle persistenten Zustand (ex Cookies, zurückgesetzt
localStorage
,IndexedDB
,Web SQL
usw.) und eine harte Aktualisierung der Seite mit tunwindow.location.reload()
. Es ist möglich, dass ein schlampiger Entwickler versehentlich oder absichtlich vertrauliche Datenwindow
im DOM usw. gespeichert hat. Das Wegblasen des gesamten dauerhaften Status und das Aktualisieren des Browsers ist die einzige Möglichkeit, um sicherzustellen, dass keine Informationen des vorherigen Benutzers an den nächsten Benutzer weitergegeben werden.(Natürlich sollten Sie als Benutzer auf einem gemeinsam genutzten Computer den Modus "Privates Surfen" verwenden, das Browserfenster selbst schließen, die Funktion "Browserdaten löschen" usw. verwenden, aber als Entwickler können wir nicht erwarten, dass dies immer jeder ist so fleißig)
quelle
Meine Problemumgehung bei der Arbeit mit Typoskript basiert auf Dans Antwort (Redux-Typisierungen machen es unmöglich,
undefined
als erstes Argument an Reducer zu übergeben, daher speichere ich den anfänglichen Root-Status in einer Konstanten zwischen).quelle
Die akzeptierte Antwort half mir, meinen Fall zu lösen. Ich stieß jedoch auf einen Fall, in dem nicht der gesamte Staat geklärt werden musste. Also - ich habe es so gemacht:
Hoffe das hilft jemand anderem :)
quelle
Nur eine Erweiterung der Antwort von @ dan-abramov . Manchmal müssen wir möglicherweise verhindern, dass bestimmte Schlüssel zurückgesetzt werden.
quelle
Eine schnelle und einfache Option, die für mich funktioniert hat, war die Verwendung von Redux-Reset . Das war unkompliziert und hat auch einige erweiterte Optionen für größere Apps.
Setup im Create Store
Versenden Sie Ihren 'Reset' in Ihrer Abmeldefunktion
Hoffe das hilft
quelle
Ich gehe davon aus, dass Redux nicht auf dieselbe Variable des Ausgangszustands verweist:
quelle
Dieser Ansatz ist sehr richtig: Zerstören Sie einen bestimmten Status "NAME", um andere zu ignorieren und zu behalten.
quelle
USER_LOGOUT
in diesem Reduzierer nachsehen und dort damit umgehen.warum benutzt du nicht einfach
return module.exports.default()
;)Hinweis: Stellen Sie sicher, dass Sie den Standardwert für die Aktion auf "
{}
OK" setzen, da Sie beim Überprüfenaction.type
der switch-Anweisung keinen Fehler feststellen möchten .quelle
Ich fand, dass die akzeptierte Antwort für mich gut funktionierte, aber den ESLint-
no-param-reassign
Fehler auslöste - https://eslint.org/docs/rules/no-param-reassignSo habe ich es stattdessen gehandhabt und sichergestellt, dass eine Kopie des Status erstellt wird (was meines Wissens die Reduxy-Aufgabe ist ...):
Aber vielleicht ist das Erstellen einer Kopie des Status, um ihn einfach an eine andere Reduzierungsfunktion zu übergeben, die eine Kopie davon erstellt, etwas zu kompliziert? Das liest sich nicht so gut, ist aber mehr auf den Punkt:
quelle
Sollten wir zusätzlich zu Dan Abramovs Antwort nicht explizit action = action = 'type:' @@ INIT '} neben state = undefined setzen. Mit dem obigen Aktionstyp gibt jeder Reduzierer den Anfangszustand zurück.
quelle
Auf dem Server habe ich eine Variable: global.isSsr = true und in jedem Reduzierer habe ich eine Konstante : initialState Um die Daten im Store zurückzusetzen, gehe ich mit jedem Reduzierer wie folgt vor: Beispiel mit appReducer.js :
Endlich auf dem Router des Servers:
quelle
Die folgende Lösung funktioniert für mich.
Zum ersten Mal auf der Einleitung unserer Anwendung ist der Reduzierer Zustand frisch und neu mit Standardinitial .
Wir müssen eine Aktion hinzufügen, die die APP-Anfangslast aufruft, um den Standardstatus beizubehalten .
Während Sie sich von der Anwendung abmelden, können Sie den Standardstatus einfach neu zuweisen, und der Reduzierer funktioniert genauso neu .
Haupt-APP-Container
Haupt-APP-Reduzierer
Beim Abmelden wird eine Aktion zum Zurücksetzen des Status aufgerufen
Hoffe das löst dein Problem!
quelle
Damit ich den Status auf den ursprünglichen Status zurücksetzen kann, habe ich den folgenden Code geschrieben:
quelle
Eine Sache, die die Lösung in der akzeptierten Antwort nicht bewirkt, ist das Löschen des Caches für parametrisierte Selektoren. Wenn Sie einen Selektor wie diesen haben:
Dann müssten Sie sie beim Abmelden folgendermaßen freigeben:
Andernfalls werden der gespeicherte Wert für den letzten Aufruf des Selektors und die Werte der letzten Parameter weiterhin gespeichert.
Codebeispiele stammen aus den ngrx-Dokumenten .
quelle
Für mich hat es am besten funktioniert, das
initialState
anstelle vonstate
:quelle
Eine andere Option ist:
'@@redux/INIT'
ist der Aktionstyp, den Redux automatisch versendet, wenn SiecreateStore
also davon ausgehen, dass Ihre Reduzierer bereits einen Standard haben. Dies würde von diesen abgefangen werden und Ihren Status neu starten. Es könnte jedoch als privates Implementierungsdetail von Redux angesehen werden, also Vorsicht beim Käufer ...quelle
Lassen Sie einfach Ihren Abmeldelink die Sitzung löschen und aktualisieren Sie die Seite. Für Ihr Geschäft wird kein zusätzlicher Code benötigt. Jedes Mal, wenn Sie den Status vollständig zurücksetzen möchten, ist eine Seitenaktualisierung eine einfache und leicht wiederholbare Methode, um damit umzugehen.
quelle
quelle
window.location.reload();
window
, in der z. B. nicht reaktionsfreudig ist