Was ist in Vuex die Logik, sowohl "Aktionen" als auch "Mutationen" zu haben?
Ich verstehe die Logik von Komponenten, die nicht in der Lage sind, den Status zu ändern (was klug erscheint), aber sowohl Aktionen als auch Mutationen zu haben, scheint, als würden Sie eine Funktion schreiben, um eine andere Funktion auszulösen und dann den Status zu ändern.
Was ist der Unterschied zwischen "Aktionen" und "Mutationen", wie arbeiten sie zusammen und außerdem bin ich neugierig, warum die Vuex-Entwickler beschlossen haben, dies so zu tun?
mutations
undactions
in der vuex-Dokumentation als Methoden zum Ändern des Status definiert sind. Sie benötigen keine Aktion, um eine Mutation zu begehen.Antworten:
Frage 1 : Warum haben sich die Vuejs-Entwickler dazu entschlossen?
Antworten:
Frage 2 : Was ist der Unterschied zwischen "Aktion" und "Mutation"?
Sehen wir uns zuerst die offizielle Erklärung an:
Hier ist meine Erklärung des oben Gesagten:
quelle
Mutationen sind synchron, während Aktionen asynchron sein können.
Anders ausgedrückt: Sie benötigen keine Aktionen, wenn Ihre Vorgänge synchron sind, andernfalls implementieren Sie sie.
quelle
Ich glaube, dass ein Verständnis der Motivationen hinter Mutationen und Aktionen es einem ermöglicht, besser zu beurteilen, wann welche und wie zu verwenden sind. Es befreit den Programmierer auch von der Last der Unsicherheit in Situationen, in denen die "Regeln" verschwimmen. Nachdem ich ein wenig über ihre jeweiligen Zwecke nachgedacht hatte, kam ich zu dem Schluss, dass es zwar definitiv falsche Wege gibt, Aktionen und Mutationen zu verwenden, aber ich glaube nicht, dass es einen kanonischen Ansatz gibt.
Versuchen wir zunächst zu verstehen, warum wir überhaupt Mutationen oder Aktionen durchlaufen.
Genau genommen können Sie die
state
direkt von Ihren Komponenten ändern . Dasstate
ist nur ein JavaScript-Objekt und es gibt nichts Magisches, das Änderungen, die Sie daran vornehmen, rückgängig macht.Auf diese Weise verteilen Sie jedoch Ihre Zustandsmutationen überall. Sie verlieren die Möglichkeit, einfach ein einzelnes Modul zu öffnen, in dem sich der Status befindet, und auf einen Blick zu sehen, welche Art von Operationen darauf angewendet werden können. Zentralisierte Mutationen lösen dieses Problem, allerdings auf Kosten einiger Kesselplatten.
Ich denke, wenn Sie etwas Kurzes durch Boilerplate ersetzen, möchten Sie, dass das Boilerplate auch klein ist. Ich gehe daher davon aus, dass Mutationen sehr dünne Umhüllungen für native Operationen des Staates sein sollen, fast ohne Geschäftslogik. Mit anderen Worten, Mutationen sollen meistens wie Setter verwendet werden.
Nachdem Sie Ihre Mutationen zentralisiert haben, haben Sie einen besseren Überblick über Ihre Statusänderungen. Da Ihr Tool (vue-devtools) auch diesen Speicherort kennt, erleichtert dies das Debuggen. Es ist auch zu beachten, dass viele Vuex-Plugins den Status nicht direkt beobachten, um Änderungen zu verfolgen, sondern sich dafür eher auf Mutationen verlassen. "Out of Bound" -Änderungen des Zustands sind für sie daher unsichtbar.
Aktionen wie Mutationen befinden sich ebenfalls im Modul des Geschäfts und können das
state
Objekt empfangen . Was bedeutet, dass sie es auch direkt mutieren könnten . Was bringt es also, beides zu haben? Wenn wir der Meinung sind, dass Mutationen klein und einfach gehalten werden müssen, bedeutet dies, dass wir ein alternatives Mittel benötigen, um eine ausgefeiltere Geschäftslogik unterzubringen. Aktionen sind das Mittel, um dies zu tun. Und da vue-devtools und Plugins, wie bereits erwähnt, Änderungen durch Mutationen kennen, sollten wir weiterhin Mutationen aus unseren Aktionen verwenden, um konsistent zu bleiben. Da Aktionen alle umfassend sein sollen und die von ihnen gekapselte Logik möglicherweise asynchron ist, ist es außerdem sinnvoll, dass Aktionen von Anfang an einfach asynchron gemacht werden.Es wird oft betont, dass Aktionen asynchron sein können, Mutationen jedoch normalerweise nicht. Sie können die Unterscheidung als Hinweis darauf betrachten, dass Mutationen für alles Synchrone verwendet werden sollten (und Aktionen für alles Asynchrone). Sie würden jedoch auf einige Schwierigkeiten stoßen, wenn Sie beispielsweise mehr als eine Mutation (synchron) festschreiben müssten oder wenn Sie mit einem Getter aus Ihren Mutationen arbeiten müssten, da Mutationsfunktionen weder Getters noch Mutationen als Argumente erhalten ...
... was zu einer interessanten Frage führt.
Ich habe noch keine zufriedenstellende Antwort auf diese Frage gefunden. Ich habe eine Erklärung des Kernteams gesehen, dass ich bestenfalls Moot gefunden habe. Wenn ich ihre Verwendung zusammenfasse, sollen Getters berechnete (und häufig zwischengespeicherte) Erweiterungen des Status sein. Mit anderen Worten, sie sind im Grunde immer noch der Staat, obwohl dies einige Vorausberechnungen erfordert und sie normalerweise schreibgeschützt sind. Zumindest werden sie so dazu ermutigt, benutzt zu werden.
Um zu verhindern, dass Mutationen direkt auf Getters zugreifen, ist eines von drei Dingen erforderlich, wenn wir von ersteren auf einige von letzteren angebotene Funktionen zugreifen müssen: (1) Entweder werden die vom Getter bereitgestellten Zustandsberechnungen an einer Stelle dupliziert, auf die zugegriffen werden kann an die Mutation (schlechter Geruch) oder (2) der berechnete Wert (oder der relevante Getter selbst) wird als explizites Argument an die Mutation (funky) weitergegeben, oder (3) die Logik des Getter selbst wird direkt innerhalb der Mutation dupliziert , ohne den zusätzlichen Vorteil des Caching, wie er vom Getter (Gestank) bereitgestellt wird.
Das Folgende ist ein Beispiel für (2), das in den meisten Szenarien, auf die ich gestoßen bin, die "am wenigsten schlechte" Option zu sein scheint.
Für mich scheint das oben Gesagte nicht nur ein bisschen verworren, sondern auch etwas "undicht" zu sein, da ein Teil des in der Aktion enthaltenen Codes eindeutig aus der internen Logik der Mutation sickert.
Meiner Meinung nach ist dies ein Hinweis auf einen Kompromiss. Ich glaube, dass es einige Herausforderungen darstellt, Mutationen automatisch Getters empfangen zu lassen. Dies kann entweder auf das Design von Vuex selbst oder auf das Werkzeug (vue-devtools et al.) Zurückgeführt werden oder auf die Aufrechterhaltung einer gewissen Abwärtskompatibilität oder auf eine Kombination aller angegebenen Möglichkeiten.
Was ich nicht glaube, ist, dass die Weitergabe von Getters an Ihre Mutationen notwendigerweise ein Zeichen dafür ist, dass Sie etwas falsch machen. Ich sehe es als einfaches "Patchen" eines der Mängel des Frameworks.
quelle
computed
ausgegeben. Sie sind schreibgeschützt. Eine schönere Möglichkeit, Mutationen anzuzeigen, besteht darin, die vorhandenen zu entfernenif else
. In den Vuex-Dokumenten heißt es, dass Sie mehr als 1commit
in einer Aktion unterbringen können . Es wäre also logisch anzunehmen, dass Sie je nach Logik eine bestimmte Mutation begehen könnten. Ich betrachte Aktionen als einen Weg, um zu diktieren, WELCHE Mutation zu feuern ist.Ich denke, die TLDR-Antwort lautet, dass Mutationen synchron / transaktional sein sollen. Wenn Sie also einen Ajax-Aufruf ausführen oder einen anderen asynchronen Code ausführen müssen, müssen Sie dies in einer Aktion tun und anschließend eine Mutation festschreiben, um den neuen Status festzulegen.
quelle
Die Hauptunterschiede zwischen Aktionen und Mutationen:
quelle
Laut dem
docs
Aktionen ähneln Mutationen , mit folgenden Unterschieden:
Betrachten Sie das folgende Snippet.
quelle
Haftungsausschluss - Ich habe gerade erst angefangen, vuejs zu verwenden, daher extrapoliere ich nur die Designabsicht.
Das Debuggen von Zeitmaschinen verwendet Snapshots des Status und zeigt eine Zeitleiste mit Aktionen und Mutationen. Theoretisch hätten wir
actions
neben einer Aufzeichnung von Zustandsgebern und Gettern auch die Mutation synchron beschreiben können. Aber dann:mutations
Transaktionen immer noch passieren , aber dann können wir sagen, dass die Transaktion verbessert werden muss, anstatt eine Race-Bedingung in den Aktionen zu sein. Anonyme Mutationen innerhalb einer Aktion können diese Art von Fehlern leichter wieder auftauchen lassen, da die asynchrone Programmierung fragil und schwierig ist.Vergleichen Sie das folgende Transaktionsprotokoll mit benannten Mutationen.
Mit einem Transaktionsprotokoll ohne benannte Mutationen:
Ich hoffe, Sie können aus diesem Beispiel die potenzielle zusätzliche Komplexität bei asynchronen und anonymen Mutationen innerhalb von Aktionen extrapolieren.
https://vuex.vuejs.org/en/mutations.html
quelle
Mutationen:
Aktionen:
Auf Redux-Art
Warum beides?
Wenn die Anwendung wächst, die Codierung und die Zeilen zunehmen. Dieses Mal müssen Sie die Logik in Aktionen und nicht in den Mutationen behandeln, da Mutationen die einzige Autorität sind, um den Status zu ändern. Sie sollte so sauber wie möglich sein.
quelle
Das hat mich auch verwirrt und ich habe eine einfache Demo gemacht.
component.vue
store.js
Nachdem ich dies untersucht hatte, kam ich zu dem Schluss, dass Mutationen eine Konvention sind, die sich nur darauf konzentriert, Daten zu ändern, um Bedenken besser zu trennen und die Protokollierung vor und nach den aktualisierten Daten zu verbessern. Während Aktionen eine Abstraktionsebene sind, die die übergeordnete Logik behandelt und dann die Mutationen entsprechend aufruft
quelle
1. Aus Dokumenten :
Die Aktionen können asynchrone Operationen enthalten, die Mutation jedoch nicht.
2.Wir rufen die Mutation auf, wir können den Zustand direkt ändern. und wir können auch in der Aktion Zustände wie folgt ändern:
Die Aktionen sind dafür ausgelegt, mehr andere Dinge zu erledigen. Wir können dort viele Dinge tun (wir können asynchrone Operationen verwenden) und dann den Status ändern, indem wir dort eine Mutation versenden.
quelle
Weil es keinen Zustand ohne Mutationen gibt! Beim Festschreiben wird eine Logik ausgeführt, die den Zustand auf vorhersehbare Weise ändert. Mutationen sind die einzige Möglichkeit, den Status festzulegen oder zu ändern (es gibt also keine direkten Änderungen!), Und außerdem müssen sie synchron sein. Diese Lösung bietet eine sehr wichtige Funktionalität: Mutationen melden sich bei devtools an. Und das bietet Ihnen eine gute Lesbarkeit und Vorhersehbarkeit!
Noch etwas - Aktionen. Wie gesagt - Aktionen begehen Mutationen. Sie ändern also nicht den Speicher, und es ist nicht erforderlich, dass diese synchron sind. Sie können jedoch ein zusätzliches Stück asynchroner Logik verwalten!
quelle
Es scheint unnötig zu sein, eine zusätzliche Ebene zu haben, um
actions
nur das aufzurufenmutations
, zum Beispiel:Wenn Sie also
actions
Anrufe anrufenlogout
, warum nicht die Mutation selbst aufrufen?Die gesamte Idee einer Aktion besteht darin, mehrere Mutationen innerhalb einer Aktion aufzurufen oder eine Ajax-Anfrage oder eine beliebige asynchrone Logik zu stellen, die Sie sich vorstellen können.
Möglicherweise haben wir Aktionen, die mehrere Netzwerkanforderungen stellen und schließlich viele verschiedene Mutationen aufrufen.
Also versuchen wir so viel Komplexität
Vuex.Store()
wie möglich in unser zu steckenactions
und das lässt unsermutations
,state
undgetters
sauberer und unkompliziert und fällt mit der Art der Modularität in Linie , die beliebten Bibliotheken wie Vue und Reagieren macht.quelle
Ich benutze Vuex seit ungefähr 3 Jahren professionell und hier ist, was ich denke, ich habe über die wesentlichen Unterschiede zwischen Aktionen und Mutationen herausgefunden, wie Sie davon profitieren können, wenn Sie sie gut zusammen verwenden, und wie Sie Ihr Leben schwieriger machen können, wenn Sie benutze es nicht gut.
Das Hauptziel von Vuex ist es, ein neues Muster zur Steuerung des Verhaltens Ihrer Anwendung anzubieten: Reaktivität. Die Idee ist, die Orchestrierung des Status Ihrer Anwendung auf ein spezielles Objekt zu verlagern: ein Geschäft. Es bietet bequeme Methoden, um Ihre Komponenten direkt mit Ihren Geschäftsdaten zu verbinden und sie nach Belieben zu verwenden. Auf diese Weise können sich Ihre Komponenten auf ihre Aufgabe konzentrieren: Definieren einer Vorlage, eines Stils und eines grundlegenden Komponentenverhaltens, die Ihrem Benutzer präsentiert werden sollen. In der Zwischenzeit bewältigt der Store die hohe Datenlast.
Dies ist jedoch nicht nur der einzige Vorteil dieses Musters. Die Tatsache, dass Speicher eine einzige Datenquelle für die gesamte Anwendung sind, bietet ein großes Potenzial für die Wiederverwendbarkeit dieser Daten über viele Komponenten hinweg. Dies ist nicht das erste Muster, mit dem versucht wird, dieses Problem der komponentenübergreifenden Kommunikation zu lösen. Es zeigt sich jedoch, dass Sie gezwungen sind, ein sehr sicheres Verhalten in Ihrer Anwendung zu implementieren, indem Sie Ihren Komponenten grundsätzlich verbieten, den Status dieser gemeinsam genutzten Daten zu ändern und zwingen Sie es stattdessen, "öffentliche Endpunkte" zu verwenden, um nach Änderungen zu fragen.
Die Grundidee ist folgende:
Davon abgesehen beginnt die Magie, wenn wir beginnen, unsere Anwendung auf diese Weise zu entwerfen. Beispielsweise:
Am Ende haben wir eine Benutzererfahrung, die als "reaktiv" eingestuft wird. Aus Sicht unseres Nutzers wurde der Artikel sofort gelöscht. Meistens erwarten wir, dass unsere Endpunkte nur funktionieren, daher ist dies perfekt. Wenn dies fehlschlägt, haben wir immer noch die Kontrolle darüber, wie unsere Anwendung reagiert , da wir das Problem des Status unserer Front-End-Anwendung erfolgreich von den tatsächlichen Daten getrennt haben.
Sie brauchen nicht immer ein Geschäft, wohlgemerkt. Wenn Sie feststellen, dass Sie Geschäfte schreiben, die so aussehen:
Mir scheint, Sie verwenden den Speicher nur als Datenspeicher und verpassen möglicherweise den Reaktivitätsaspekt, indem Sie nicht zulassen, dass er auch die Kontrolle über Variablen übernimmt, auf die Ihre Anwendung reagiert. Grundsätzlich können und sollten Sie wahrscheinlich einige Codezeilen, die in Ihren Komponenten geschrieben sind, in Ihre Filialen auslagern.
quelle