Action Vuex vs Mutations

173

Dans Vuex, quelle est la logique d'avoir à la fois des «actions» et des «mutations»?

Je comprends la logique des composants ne pouvant pas modifier l'état (ce qui semble intelligent), mais avoir à la fois des actions et des mutations semble que vous écriviez une fonction pour déclencher une autre fonction, pour ensuite modifier l'état.

Quelle est la différence entre «actions» et «mutations», comment fonctionnent-elles ensemble, et plus encore, je suis curieux de savoir pourquoi les développeurs de Vuex ont décidé de le faire de cette façon?

Kobi
la source
2
Voir "On To Actions", je pense: vuex.vuejs.org/en/mutations.html#on-to-actions
Roy J
discussion connexe: github.com/vuejs/vuex/issues/587
chuck911
1
Vous ne pouvez pas modifier directement l'état du magasin. La seule façon de changer l'état d'un magasin est de commettre explicitement des mutations. Pour cela, nous avons besoin d'actions pour commettre des mutations.
Suresh Sapkota
1
@SureshSapkota cette déclaration est très déroutante, car les deux mutationset actionssont définis dans la documentation de vuex comme des méthodes de changement d'état. Vous n'avez pas besoin d'une action pour commettre une mutation.
Graham
1
Les mutations, comme son nom l'indique, sont utilisées pour modifier / muter votre objet d'état. Les actions sont assez similaires aux mutations, mais au lieu de muter l'état, les actions commettent des mutations. Les actions peuvent contenir n'importe quel code asynchrone arbitraire ou logique métier . Vuex recommande que l'objet d'état ne soit muté qu'à l'intérieur des fonctions de mutation. Il est également recommandé de ne pas exécuter de code lourd ou bloquant dans les fonctions de mutation car il est de nature synchrone .
Emmanuel Neni le

Réponses:

221

Question 1 : Pourquoi les développeurs de Vuejs ont décidé de le faire de cette façon?

Répondre:

  1. Lorsque votre application devient volumineuse et que plusieurs développeurs travaillent sur ce projet, vous constaterez que le "state manage" (en particulier le "global state"), deviendra de plus en plus compliqué.
  2. La méthode vuex (tout comme Redux dans react.js ) offre un nouveau mécanisme pour gérer l'état, conserver l'état et "enregistrer et suivre" (cela signifie que chaque action qui modifie l'état peut être suivie par l' outil de débogage: vue-devtools )

Question 2 : Quelle est la différence entre «action» et «mutation»?

Voyons d'abord l'explication officielle:

Mutations:

Les mutations Vuex sont essentiellement des événements: chaque mutation a un nom et un gestionnaire.

import Vuex from 'vuex'

const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    INCREMENT (state) {
      // mutate state
      state.count++
    }
  }
})

Actions: les actions ne sont que des fonctions qui envoient des mutations.

// the simplest action
function increment (store) {
  store.dispatch('INCREMENT')
}

// a action with additional arguments
// with ES2015 argument destructuring
function incrementBy ({ dispatch }, amount) {
  dispatch('INCREMENT', amount)
}

Voici mon explication de ce qui précède:

  • la mutation est le seul moyen de modifier l'état
  • la mutation ne se soucie pas de la logique métier, elle se soucie juste de "l'état"
  • l'action est une logique métier
  • l'action peut envoyer plus d'une mutation à la fois, elle implémente simplement la logique métier, elle ne se soucie pas de la modification des données (qui gèrent par mutation)
Kaicui
la source
80
Le fait qu'une action "est la logique métier" et puisse envoyer plusieurs mutations à la fois est utile. C'est la réponse que je recherchais. Je vous remercie.
Kobi le
11
vous cuys dites que vous "expédiez une mutation". Le libellé correct que vous COMMITEZ n'est-il pas une mutation?
ProblemsOfSumit
4
Vous envoyez des actions et commettez des mutations.
eirik
4
dispatch ne fonctionne plus en vue 2.0 pour la mutation, vous devez valider une mutation dans l'action.
SKLTFZ
18
@Kaicui Il manque une note à cette réponse sur les mutations toujours synchrones et les actions potentiellement asynchrones. A part ça, une bonne réponse!
décates
58

Les mutations sont synchrones, tandis que les actions peuvent être asynchrones.

Pour le dire autrement: vous n'avez pas besoin d'actions si vos opérations sont synchrones, sinon implémentez-les.

Bas
la source
2
cela répond en fait à une question que j'allais poser, sur la façon dont l'exemple todomvc n'utilise aucune action.
sksallaj
7
« Vous n'avez pas besoin d' actions si vos opérations sont synchrones » : Ce n'est pas vrai: vous faites des actions de besoin si vous voulez composer plusieurs mutations du même module, parce que vous ne pouvez pas appeler une autre action d'une action.
Raymundus
1
La suite évidente à cette réponse serait "alors pourquoi ne pas simplement avoir des actions et se débarrasser des mutations"
Michael Mrozek
35

Je crois qu'avoir une compréhension des motivations derrière les mutations et les actions permet de mieux juger quand utiliser lesquelles et comment. Cela libère également le programmeur du fardeau de l'incertitude dans les situations où les «règles» deviennent floues. Après avoir un peu réfléchi à leurs objectifs respectifs, je suis arrivé à la conclusion que, bien qu'il puisse certainement y avoir de mauvaises façons d'utiliser les actions et les mutations, je ne pense pas qu'il y ait une approche canonique.

Essayons d'abord de comprendre pourquoi nous subissons même des mutations ou des actions.

Pourquoi passer par le passe-partout en premier lieu? Pourquoi ne pas changer d'état directement dans les composants?

À proprement parler, vous pouvez modifier le statedirectement depuis vos composants. Le staten'est qu'un objet JavaScript et il n'y a rien de magique qui annulera les modifications que vous y apportez.

// Yes, you can!
this.$store.state['products'].push(product)

Cependant, en faisant cela, vous dispersez vos mutations d'état partout. Vous perdez la possibilité d'ouvrir simplement un seul module abritant l'état et de voir d'un coup d'œil quel type d'opérations peut être appliqué. Le fait d'avoir des mutations centralisées résout ce problème, mais au prix d'un passe-partout.

// so we go from this
this.$store.state['products'].push(product)

// to this
this.$store.commit('addProduct', {product})

...
// and in store
addProduct(state, {product}){
    state.products.push(product)
}
...

Je pense que si vous remplacez quelque chose de court par du passe-partout, vous voudrez que le passe-partout soit également petit. Je suppose donc que les mutations sont censées être des enveloppes très minces autour des opérations natives sur l'état, avec presque aucune logique métier. En d'autres termes, les mutations sont destinées à être principalement utilisées comme des setters.

Maintenant que vous avez centralisé vos mutations, vous avez une meilleure vue d'ensemble de vos changements d'état et puisque vos outils (vue-devtools) sont également conscients de cet emplacement, cela facilite le débogage. Il convient également de garder à l'esprit que de nombreux plugins de Vuex ne surveillent pas directement l'état pour suivre les changements, ils s'appuient plutôt sur des mutations pour cela. Les changements d'état «hors limites» leur sont donc invisibles.

Alors mutations, actionsquelle est la différence de toute façon?

Les actions, comme les mutations, résident également dans le module du magasin et peuvent recevoir l' stateobjet. Ce qui implique qu'ils pourraient également le muter directement. Alors, quel est l'intérêt d'avoir les deux? Si nous pensons que les mutations doivent rester petites et simples, cela implique que nous avons besoin d'un moyen alternatif pour héberger une logique métier plus élaborée. Les actions sont les moyens de le faire. Et comme nous l'avons établi précédemment, vue-devtools et les plugins sont conscients des changements via les mutations, pour rester cohérent, nous devons continuer à utiliser les mutations à partir de nos actions. En outre, étant donné que les actions sont censées être toutes englobantes et que la logique qu'elles encapsulent peut être asynchrone, il est logique que les actions soient également simplement rendues asynchrones dès le départ.

Il est souvent souligné que les actions peuvent être asynchrones, alors que les mutations ne le sont généralement pas. Vous pouvez décider de voir la distinction comme une indication que les mutations doivent être utilisées pour tout ce qui est synchrone (et des actions pour tout ce qui est asynchrone); cependant, vous rencontriez des difficultés si, par exemple, vous deviez commettre plus d'une mutation (de manière synchrone), ou si vous deviez travailler avec un Getter à partir de vos mutations, car les fonctions de mutation ne reçoivent ni Getters ni Mutations comme arguments ...

... ce qui conduit à une question intéressante.

Pourquoi les mutations ne reçoivent-elles pas de Getters?

Je n'ai pas encore trouvé de réponse satisfaisante à cette question. J'ai vu des explications de l'équipe de base que je trouvais au mieux sans objet. Si je résume leur utilisation, les Getters sont censés être des extensions calculées (et souvent mises en cache) de l'état. En d'autres termes, ils sont fondamentalement toujours l'état, bien que cela nécessite un calcul initial et ils sont normalement en lecture seule. C'est du moins ainsi qu'ils sont encouragés à être utilisés.

Ainsi, empêcher les mutations d'accéder directement aux Getters signifie que l'une des trois choses est désormais nécessaire, si nous devons accéder à partir du premier à certaines fonctionnalités offertes par le second: (1) soit les calculs d'état fournis par le Getter sont dupliqués dans un endroit accessible. à la mutation (mauvaise odeur), ou (2) la valeur calculée (ou le Getter lui-même) est transmise comme argument explicite à la mutation (funky), ou (3) la logique du Getter elle-même est dupliquée directement dans la mutation , sans l'avantage supplémentaire de la mise en cache fournie par le Getter (puanteur).

Ce qui suit est un exemple de (2), qui dans la plupart des scénarios que j'ai rencontrés semble l'option "la moins mauvaise".

state:{
    shoppingCart: {
        products: []
    }
},

getters:{
    hasProduct(state){
        return function(product) { ... }
    }
}

actions: {
    addProduct({state, getters, commit, dispatch}, {product}){

        // all kinds of business logic goes here

        // then pull out some computed state
        const hasProduct = getters.hasProduct(product)
        // and pass it to the mutation
        commit('addProduct', {product, hasProduct})
    }
}

mutations: {
    addProduct(state, {product, hasProduct}){ 
        if (hasProduct){
            // mutate the state one way
        } else {
            // mutate the state another way 
        }
    }
}

Pour moi, ce qui précède me semble non seulement un peu alambiqué, mais aussi quelque peu «fuyant», car une partie du code présent dans l'action suinte clairement de la logique interne de la mutation.

À mon avis, c'est le signe d'un compromis. Je pense que permettre à Mutations de recevoir automatiquement des Getters présente certains défis. Cela peut être soit pour la conception de Vuex lui-même, soit pour les outils (vue-devtools et al), ou pour maintenir une compatibilité descendante, ou une combinaison de toutes les possibilités énoncées.

Ce que je ne crois pas, c'est que passer vous-même Getters à vos mutations est nécessairement un signe que vous faites quelque chose de mal. Je le vois simplement comme un «correctif» de l'une des lacunes du cadre.

Michael Ekoka
la source
1
Pour moi, c'est la meilleure réponse. Ce n'est qu'après l'avoir lu que j'ai eu ce "clic" que vous ressentez lorsque vous sentez que vous avez compris quelque chose.
Robert Kusznier
Les Getters sont essentiellement des computedsorties. Ils sont en lecture seule. Une meilleure façon de visualiser les mutations pourrait être de supprimer les if elsefichiers. La documentation vuex indique que vous pouvez héberger plus d' commitun élément dans une action. Il serait donc logique de supposer que vous pourriez commettre certaines mutations en fonction de la logique. Je considère les actions comme un moyen de dicter QUELLE mutation se déclenche.
Tamb
@Tamb: State et Getters offrent tous deux des données contextuelles. Il est logique qu’ils soient interrogés avant de décider comment modifier l’État. Lorsque cette information peut être extraite entièrement de l'État, il est logique que toute la logique soit encapsulée dans une seule mutation, car elle a accès à l'État. Il s'agit d'une procédure standard d'exploitation pour un poseur. Ce qui a moins de sens, c'est d'avoir une approche radicalement différente simplement parce que nous devons maintenant interroger un Getter pour obtenir des informations similaires.
Michael Ekoka
@Tamb: Ce que vous suggérez, c'est que lorsque nous devons interroger les Getters, nous devons changer le modèle ci-dessus et déplacer la logique de sélection vers une action proxy qui peut accéder au Getter et peut coller ensemble un tas de minuscules mutations stupides. Cela fonctionne, mais c'est toujours détourné et ne résout pas la mauvaise odeur à laquelle je fais référence dans ma réponse, cela le déplace simplement ailleurs.
Michael Ekoka
La documentation indique que pour utiliser des getters lorsque vous devez calculer l'état. Il semble donc correct aujourd'hui qu'ils sont similaires aux propriétés calculées. Idk ce que vous voulez dire en disant que l'action peut coller des mutations. La documentation dit clairement de mettre la logique métier à l'intérieur des actions.
Tamb
15

Je pense que la réponse TLDR est que les mutations sont censées être synchrones / transactionnelles. Donc, si vous avez besoin d'exécuter un appel Ajax, ou de faire tout autre code asynchrone, vous devez le faire dans une action, puis valider une mutation après, pour définir le nouvel état.

Noah Namey
la source
1
Cela ressemble à un résumé de la documentation; avec lequel il n'y a rien de mal. Cependant, le problème avec cette réponse est que ce qu'elle affirme n'est pas nécessairement vrai. Vous POUVEZ modifier l'état à l'intérieur d'une mutation lors de l'appel d'une fonction asynchrone / AJAX, qui peut ensuite être modifiée dans le rappel complet. Je pense que c'est ce qui cause tant de confusion sur les raisons pour lesquelles les actions devraient être utilisées pour les meilleures pratiques de développement lorsque vous travaillez avec Vuex. Je sais que c'était certainement une source de confusion pour moi lorsque j'ai commencé à travailler avec Vuex.
Erutan409
8

Les principales différences entre les actions et les mutations:

  1. À l'intérieur des actions, vous pouvez exécuter du code asynchrone mais pas dans des mutations. Utilisez donc des actions pour le code asynchrone, sinon utilisez des mutations.
  2. À l'intérieur des actions, vous pouvez accéder aux getters, à l'état, aux mutations (les valider), aux actions (les distribuer) dans les mutations, vous pouvez accéder à l'état. Donc, si vous souhaitez accéder uniquement à l'état, utilisez des mutations, sinon utilisez des actions.
roli roli
la source
5

Selon le docs

Les actions sont similaires aux mutations , les différences étant que:

  • Au lieu de muter l'état, les actions commettent des mutations.
  • Les actions peuvent contenir des opérations asynchrones arbitraires .

Considérez l'extrait suivant.

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++               //Mutating the state. Must be synchronous
    }
  },
  actions: {
    increment (context) {
      context.commit('increment') //Committing the mutations. Can be asynchronous.
    }
  }
})

Les gestionnaires d'actions ( incrémentés ) reçoivent un objet de contexte qui expose le même ensemble de méthodes / propriétés sur l'instance de magasin, vous pouvez donc appeler context.commit pour valider une mutation, ou accéder à l'état et aux getters via context.state et context.getters

Abdullah Khan
la source
1
est un appel possible de la fonction 'mutation', une méthode du composant vuejs?
Alberto Acuña
@ AlbertoAcuña J'ai la même question, parce que quand j'essaye de faire ça, ça jette une erreur que la mutation locale n'est pas définie.
Rutwick Gangurde le
5

Clause de non-responsabilité - Je viens juste de commencer à utiliser vuejs, il ne s'agit donc que d'extrapoler l'intention de conception.

Le débogage Time Machine utilise des instantanés de l'état et montre une chronologie des actions et des mutations. En théorie, nous aurions pu avoir juste à actionscôté d'un enregistrement des setters et des getters d'État pour décrire de manière synchrone la mutation. Mais alors:

  • Nous aurions des entrées impures (résultats asynchrones) qui causaient les setters et les getters. Ce serait difficile à suivre logiquement et différents setters et getters asynchrones peuvent interagir de manière surprenante. Cela peut encore arriver avec les mutationstransactions, mais nous pouvons alors dire que la transaction doit être améliorée au lieu d'être une condition de concurrence dans les actions. Les mutations anonymes à l'intérieur d'une action pourraient plus facilement refaire surface ces types de bogues car la programmation asynchrone est fragile et difficile.
  • Le journal des transactions serait difficile à lire car il n'y aurait pas de nom pour les changements d'état. Ce serait beaucoup plus semblable à un code et moins anglais, sans les regroupements logiques de mutations.
  • Il peut être plus délicat et moins performant d'enregistrer par instrument une mutation sur un objet de données, par opposition à maintenant où il y a des points de diff définis de manière synchrone - avant et après l'appel de la fonction de mutation. Je ne sais pas quelle est l'ampleur du problème.

Comparez le journal de transactions suivant avec les mutations nommées.

Action: FetchNewsStories
Mutation: SetFetchingNewsStories
Action: FetchNewsStories [continuation]
Mutation: DoneFetchingNewsStories([...])

Avec un journal de transactions sans mutations nommées:

Action: FetchNewsStories
Mutation: state.isFetching = true;
Action: FetchNewsStories [continuation]
Mutation: state.isFetching = false;
Mutation: state.listOfStories = [...]

J'espère que vous pourrez extrapoler à partir de cet exemple la complexité supplémentaire potentielle des actions asynchrones et anonymes dans les actions.

https://vuex.vuejs.org/en/mutations.html

Imaginez maintenant que nous déboguons l'application et examinons les journaux de mutation de devtool. Pour chaque mutation enregistrée, le devtool devra capturer un instantané «avant» et «après» de l'état. Cependant, le rappel asynchrone dans l'exemple de mutation ci-dessus rend cela impossible: le rappel n'est pas encore appelé lorsque la mutation est validée, et il n'y a aucun moyen pour l'outil de développement de savoir quand le rappel sera réellement appelé - toute mutation d'état effectuée dans le rappel est essentiellement non traçable!

ubershmekel
la source
4

Mutations:

Can update the state. (Having the Authorization to change the state).

Actions:

Actions are used to tell "which mutation should be triggered"

Dans Redux Way

Mutations are Reducers
Actions are Actions

Pourquoi les deux ??

Lorsque l'application grandit, le codage et les lignes augmenteront, Cette fois-là, vous devrez gérer la logique dans Actions et non dans les mutations car les mutations sont la seule autorité pour changer l'état, cela devrait être aussi propre que possible.

Gopinath Kaliappan
la source
2

Cela m'a aussi dérouté, alors j'ai fait une simple démo.

component.vue

<template>
    <div id="app">
        <h6>Logging with Action vs Mutation</h6>
        <p>{{count}}</p>
        <p>
            <button @click="mutateCountWithAsyncDelay()">Mutate Count directly with delay</button>
        </p>
        <p>
            <button @click="updateCountViaAsyncAction()">Update Count via action, but with delay</button>
        </p>
        <p>Note that when the mutation handles the asynchronous action, the "log" in console is broken.</p>
        <p>When mutations are separated to only update data while the action handles the asynchronous business
            logic, the log works the log works</p>
    </div>
</template>

<script>

        export default {
                name: 'app',

                methods: {

                        //WRONG
                        mutateCountWithAsyncDelay(){
                                this.$store.commit('mutateCountWithAsyncDelay');
                        },

                        //RIGHT
                        updateCountViaAsyncAction(){
                                this.$store.dispatch('updateCountAsync')
                        }
                },

                computed: {
                        count: function(){
                                return this.$store.state.count;
                        },
                }

        }
</script>

store.js

import 'es6-promise/auto'
import Vuex from 'vuex'
import Vue from 'vue';

Vue.use(Vuex);

const myStore = new Vuex.Store({
    state: {
        count: 0,
    },
    mutations: {

        //The WRONG way
        mutateCountWithAsyncDelay (state) {
            var log1;
            var log2;

            //Capture Before Value
            log1 = state.count;

            //Simulate delay from a fetch or something
            setTimeout(() => {
                state.count++
            }, 1000);

            //Capture After Value
            log2 = state.count;

            //Async in mutation screws up the log
            console.log(`Starting Count: ${log1}`); //NRHG
            console.log(`Ending Count: ${log2}`); //NRHG
        },

        //The RIGHT way
        mutateCount (state) {
            var log1;
            var log2;

            //Capture Before Value
            log1 = state.count;

            //Mutation does nothing but update data
            state.count++;

            //Capture After Value
            log2 = state.count;

            //Changes logged correctly
            console.log(`Starting Count: ${log1}`); //NRHG
            console.log(`Ending Count: ${log2}`); //NRHG
        }
    },

    actions: {

        //This action performs its async work then commits the RIGHT mutation
        updateCountAsync(context){
            setTimeout(() => {
                context.commit('mutateCount');
            }, 1000);
        }
    },
});

export default myStore;

Après avoir recherché cela, la conclusion à laquelle je suis arrivé est que les mutations sont une convention centrée uniquement sur la modification des données pour mieux séparer les préoccupations et améliorer la journalisation avant et après les données mises à jour. Alors que les actions sont une couche d'abstraction qui gère la logique de niveau supérieur et appelle ensuite les mutations de manière appropriée

Patinoire Nathaniel
la source
1

J'utilise Vuex professionnellement depuis environ 3 ans, et voici ce que je pense avoir compris sur les différences essentielles entre les actions et les mutations, comment vous pouvez bénéficier de bien les utiliser ensemble et comment vous pouvez rendre votre vie plus difficile si vous ne l'utilisez pas bien.

L'objectif principal de Vuex est de proposer un nouveau modèle pour contrôler le comportement de votre application: la réactivité. L'idée est de décharger l'orchestration de l'état de votre application vers un objet spécialisé: un magasin. Il fournit des méthodes pratiques pour connecter vos composants directement aux données de votre magasin à utiliser à leur convenance. Cela permet à vos composants de se concentrer sur leur travail: définir un modèle, un style et un comportement de base des composants à présenter à votre utilisateur. Pendant ce temps, le magasin gère la lourde charge de données.

Ce n'est pas seulement le seul avantage de ce modèle. Le fait que les magasins soient une source unique de données pour l'intégralité de votre application offre un grand potentiel de réutilisation de ces données à travers de nombreux composants. Ce n'est pas le premier modèle qui tente de résoudre ce problème de communication inter-composants, mais là où il brille, c'est qu'il vous oblige à implémenter un comportement très sûr à votre application en interdisant fondamentalement à vos composants de modifier l'état de ces données partagées , et forcez-le plutôt à utiliser des «points de terminaison publics» pour demander des modifications.

L'idée de base est la suivante:

  • Le magasin a un état interne, auquel les composants ne devraient jamais accéder directement (mapState est effectivement banni)
  • Le magasin a des mutations, qui sont une modification synchrone de l'état interne. Le seul travail d'une mutation est de modifier l'état. Ils ne devraient être appelés qu'à partir d'une action. Ils doivent être nommés pour décrire les événements qui sont arrivés à l'état (ORDER_CANCELED, ORDER_CREATED). Gardez-les courts et doux. Vous pouvez les parcourir en utilisant l'extension de navigateur Vue Devtools (c'est également idéal pour le débogage!)
  • Le magasin a également des actions, qui doivent être asynchrones ou renvoyer une promesse. Ce sont les actions que vos composants appelleront lorsqu'ils voudront modifier l'état de l'application. Ils doivent être nommés avec des actions orientées métier (verbes, ie cancelOrder, createOrder). C'est ici que vous validez et envoyez vos demandes. Chaque action peut appeler différents commits à différentes étapes s'il est nécessaire de changer l'état.
  • Enfin, le magasin a des getters, qui sont ce que vous utilisez pour exposer votre état à vos composants. Attendez-vous à ce qu'ils soient largement utilisés dans de nombreux composants à mesure que votre application se développe. Vuex met fortement en cache les getters pour éviter les cycles de calcul inutiles (tant que vous n'ajoutez pas de paramètres à votre getter - essayez de ne pas utiliser de paramètres) alors n'hésitez pas à les utiliser intensivement. Assurez-vous simplement de donner des noms qui décrivent le plus fidèlement possible l'état actuel de l'application.

Cela étant dit, la magie commence lorsque nous commençons à concevoir notre application de cette manière. Par exemple:

  • Nous avons un composant qui offre une liste de commandes à l'utilisateur avec la possibilité de supprimer ces commandes
  • Les composants ont mappé un getter de magasin (deletableOrders), qui est un tableau d'objets avec des identifiants
  • Le composant a un bouton sur chaque ligne de commandes, et son clic est mappé à une action de magasin (deleteOrder) qui lui passe l'objet de commande (qui, nous nous en souviendrons, provient de la liste du magasin elle-même)
  • L'action store deleteOrder effectue les opérations suivantes:
    • il valide la suppression
    • il stocke la commande à supprimer temporairement
    • il valide la mutation ORDER_DELETED avec la commande
    • il envoie l'appel API pour supprimer réellement la commande (oui, APRÈS avoir modifié l'état!)
    • il attend la fin de l'appel (l'état est déjà mis à jour) et en cas d'échec, on appelle la mutation ORDER_DELETE_FAILED avec l'ordre que nous avons gardé précédemment.
  • La mutation ORDER_DELETED supprimera simplement la commande donnée de la liste des commandes supprimables (ce qui mettra à jour le getter)
  • La mutation ORDER_DELETE_FAILED la remet simplement et se modifie en état pour notifier l'erreur (un autre composant, la notification d'erreur, suivrait cet état pour savoir quand s'afficher)

Au final, nous avons une expérience utilisateur jugée «réactive». Du point de vue de notre utilisateur, l'élément a été supprimé immédiatement. La plupart du temps, nous nous attendons à ce que nos points de terminaison fonctionnent, c'est donc parfait. En cas d'échec, nous avons toujours un certain contrôle sur la façon dont notre application réagira , car nous avons réussi à séparer le problème de l'état de notre application frontale avec les données réelles.

Vous n'avez pas toujours besoin d'un magasin, remarquez. Si vous trouvez que vous écrivez des magasins qui ressemblent à ceci:

export default {
  state: {
    orders: []
  },
  mutations: {
    ADD_ORDER (state, order) {
       state.orders.push(order)
    },
    DELETE_ORDER (state, orderToDelete) {
       state.orders = state.orders.filter(order => order.id !== orderToDelete.id)
    }
  },
  actions: {
    addOrder ({commit}, order) {
      commit('ADD_ORDER', order)
    },
    deleteOrder ({commit}, order) {
      commit('DELETE_ORDER', order)
    }
  },
  getters: {
    orders: state => state.orders
  }
}

Il me semble que vous n'utilisez le magasin que comme magasin de données et que vous manquez peut-être l'aspect réactivité de celui-ci, en ne le laissant pas également prendre le contrôle des variables auxquelles votre application réagit. Fondamentalement, vous pouvez et devriez probablement décharger certaines lignes de code écrites dans vos composants vers vos magasins.

Alex
la source
0

1. à partir de la documentation :

Les actions sont similaires aux mutations, les différences étant que:

  • Au lieu de muter l'état, les actions commettent des mutations.
  • Les actions peuvent contenir des opérations asynchrones arbitraires.

Les actions peuvent contenir des opérations asynchrones, mais pas la mutation.

2.Nous invoquons la mutation, nous pouvons changer l'état directement. et nous pouvons également dans l'action pour changer les états comme ceci:

actions: {
  increment (store) {
    // do whatever ... then change the state
    store.dispatch('MUTATION_NAME')
  }
}

les Actions sont conçues pour gérer plus d'autres choses, nous pouvons y faire beaucoup de choses (nous pouvons utiliser des opérations asynchrones) puis changer d'état en y envoyant une mutation.

avion
la source
0

Parce qu'il n'y a pas d'état sans mutations! Lorsqu'il est engagé - un morceau de logique, qui change l'état de manière prévisible, est exécuté. Les mutations sont le seul moyen de définir ou de modifier l'état (il n'y a donc pas de changements directs!), Et de plus - elles doivent être synchrones. Cette solution entraîne une fonctionnalité très importante: les mutations se connectent aux outils de développement. Et cela vous offre une grande lisibilité et prévisibilité!

Encore une chose - des actions. Comme on l'a dit, les actions commettent des mutations. Ils ne changent donc pas de magasin et il n'est pas nécessaire que ceux-ci soient synchrones. Mais, ils peuvent gérer un morceau supplémentaire de logique asynchrone!

Sumit Patel
la source
0

Il peut sembler inutile d'avoir une couche supplémentaire de actionsjuste pour appeler mutations, par exemple:

const actions = {
  logout: ({ commit }) => {
    commit("setToken", null);
  }
};

const mutations = {
  setToken: (state, token) => {
    state.token = token;
  }
};

Donc, si l'appel actionsappelle logout, pourquoi ne pas appeler la mutation elle-même?

L'idée même d'une action est d'appeler plusieurs mutations à partir d'une action ou de faire une requête Ajax ou tout type de logique asynchrone que vous pouvez imaginer.

Nous pourrions éventuellement avoir des actions qui font plusieurs requêtes réseau et appellent éventuellement de nombreuses mutations différentes.

Nous essayons donc de choses que la complexité beaucoup plus de notre Vuex.Store()possible dans nos actionsce qui laisse notre mutations, stateet plus getterspropre et simple et tombe en ligne avec le genre de modularité qui rend les bibliothèques comme Vue et React populaire.

Daniel
la source