Vuex Action vs Mutations


173

In Vuex, qual è la logica di avere sia "azioni" che "mutazioni"?

Comprendo la logica dei componenti che non sono in grado di modificare lo stato (che sembra intelligente), ma avere azioni e mutazioni sembra che tu stia scrivendo una funzione per attivare un'altra funzione, per poi alterare lo stato.

Qual è la differenza tra "azioni" e "mutazioni", come funzionano insieme e più, sono curioso di sapere perché gli sviluppatori di Vuex hanno deciso di farlo in questo modo?


2
Vedi "On To Actions", penso: vuex.vuejs.org/en/mutations.html#on-to-actions
Roy J

discussione correlata: github.com/vuejs/vuex/issues/587
chuck911

1
Non è possibile mutare direttamente lo stato del negozio. L'unico modo per cambiare lo stato di un negozio è commettere esplicitamente mutazioni. Per questo abbiamo bisogno di azioni per commettere mutazioni.
Suresh Sapkota,

1
@SureshSapkota questa affermazione è molto confusa, in quanto entrambi mutationse actionssono confinati nella documentazione di Vuex come metodi per cambiare stato. Non hai bisogno di un'azione per commettere una mutazione.
Graham,

1
Le mutazioni, come suggerisce il nome, vengono utilizzate per modificare / mutare l'oggetto stato. Le azioni sono abbastanza simili alle mutazioni, ma invece di mutare lo stato, le azioni commettono mutazioni. Le azioni possono contenere qualsiasi codice asincrono arbitrario o logica aziendale . Vuex raccomanda che l'oggetto stato debba essere mutato solo all'interno delle funzioni di Mutazione. Si consiglia inoltre di non eseguire alcun codice pesante o di blocco all'interno delle funzioni di Mutazione poiché è di natura sincrona .
Emmanuel Neni il

Risposte:


221

Domanda 1 : Perché gli sviluppatori Vuejs hanno deciso di farlo in questo modo?

Risposta:

  1. Quando la tua applicazione diventa grande e quando ci sono più sviluppatori che lavorano su questo progetto, troverai che "gestire lo stato" (specialmente "stato globale") diventerà sempre più complicato.
  2. Il modo vuex (proprio come Redux in reazione.js ) offre un nuovo meccanismo per gestire lo stato, mantenere lo stato e "salvare e tracciabile" (ciò significa che ogni azione che modifica lo stato può essere tracciata dallo strumento di debug: vue-devtools )

Domanda 2 : Qual è la differenza tra "azione" e "mutazione"?

Vediamo prima la spiegazione ufficiale:

mutazioni:

Le mutazioni Vuex sono essenzialmente eventi: ogni mutazione ha un nome e un gestore.

import Vuex from 'vuex'

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

Azioni: le azioni sono solo funzioni che inviano mutazioni.

// 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)
}

Ecco la mia spiegazione di quanto sopra:

  • la mutazione è l' unico modo per modificare lo stato
  • alla mutazione non interessa la logica aziendale, si preoccupa solo dello "stato"
  • l'azione è una logica aziendale
  • l'azione può inviare più di 1 mutazione alla volta, implementa solo la logica aziendale, non si preoccupa della modifica dei dati (che gestiscono per mutazione)

80
È utile il fatto che un'azione "sia la logica aziendale" e possa inviare più mutazioni alla volta. Questa è la risposta che stavo cercando. Grazie.
Kobi,

11
voi cuys state dicendo che "inviate una mutazione". La formulazione corretta che COMMIT non è una mutazione?
ProblemsOfSumit

4
Spedisci azioni e commetti mutazioni.
eirik,

4
la spedizione non funziona più in vue 2.0 per mutazione, è necessario commettere una mutazione nell'azione.
SKLTFZ,

18
@Kaicui A questa risposta manca una nota sul fatto che le mutazioni sono sempre sincrone e le azioni potenzialmente asincrone. A parte questo, una buona risposta!
decide il

58

Le mutazioni sono sincrone, mentre le azioni possono essere asincrone.

Per dirla in un altro modo: non sono necessarie azioni se le operazioni sono sincrone, altrimenti implementarle.


2
questo in realtà risponde a una domanda che avrei fatto, su come l'esempio todomvc non faccia uso di azioni.
sksallaj,

7
'Non hai bisogno di azioni, se le operazioni sono sincroni' : Questo non è vero: si fa azioni serve se volete comporre mutazioni multiple dallo stesso modulo, perché non si può chiamare un'altra azione da un'azione.
Raymundus,

1
L'ovvio seguito a questa risposta sarebbe "allora perché non semplicemente agire e sbarazzarsi delle mutazioni"
Michael Mrozek,

34

Credo che avere una comprensione delle motivazioni alla base di mutazioni e azioni ci permetta di giudicare meglio quando usare quale e come. Inoltre, libera il programmatore dall'onere dell'incertezza nelle situazioni in cui le "regole" diventano confuse. Dopo aver ragionato un po 'sui loro rispettivi scopi, sono giunto alla conclusione che sebbene possano esserci sicuramente modi sbagliati di usare Azioni e Mutazioni, non penso che ci sia un approccio canonico.

Prima proviamo a capire perché passiamo persino attraverso le mutazioni o le azioni.

Perché in primo luogo passare attraverso la piastra della caldaia? Perché non cambiare lo stato direttamente nei componenti?

A rigor di termini potresti cambiare statedirettamente dai tuoi componenti. Il stateè solo un oggetto JavaScript e non c'è nulla di magico che annullare le modifiche apportate ad esso.

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

Tuttavia, facendo questo spargi le tue mutazioni di stato in tutto il luogo. Si perde la possibilità di aprire semplicemente un singolo modulo che ospita lo stato e, a colpo d'occhio, vedere quale tipo di operazioni può essere applicato ad esso. Avere mutazioni centralizzate risolve questo, anche se a scapito di alcune piastre di caldaia.

// 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)
}
...

Penso che se sostituisci qualcosa di corto con il boilerplate, vuoi che anche il plateplate sia piccolo. Presumo quindi che le mutazioni debbano essere involucri molto sottili attorno alle operazioni native sullo stato, con quasi nessuna logica aziendale. In altre parole, le mutazioni sono pensate per essere usate principalmente come setter.

Ora che hai centralizzato le tue mutazioni, hai una migliore visione d'insieme dei cambiamenti di stato e poiché i tuoi strumenti (vue-devtools) sono anche consapevoli di quella posizione, questo rende il debugging più semplice. Vale anche la pena ricordare che molti plugin di Vuex non guardano direttamente lo stato per tracciare i cambiamenti, ma si affidano piuttosto alle mutazioni. Le modifiche allo stato "fuori limite" sono quindi invisibili per loro.

Quindi mutations, actionsqual è la differenza comunque?

Le azioni, come le mutazioni, risiedono anche nel modulo del negozio e possono ricevere l' stateoggetto. Ciò implica che potrebbero anche mutarlo direttamente. Allora, qual è il punto di avere entrambi? Se riteniamo che le mutazioni debbano essere mantenute piccole e semplici, ciò implica che abbiamo bisogno di mezzi alternativi per ospitare una logica aziendale più elaborata. Le azioni sono i mezzi per farlo. E poiché come abbiamo stabilito in precedenza, vue-devtools e plugin sono consapevoli dei cambiamenti attraverso le mutazioni, per rimanere coerenti dovremmo continuare a utilizzare le mutazioni dalle nostre azioni. Inoltre, poiché le azioni sono intese come onnicomprensive e che la logica che incapsulano può essere asincrona, ha senso che anche le azioni diventerebbero asincrone dall'inizio.

Viene spesso sottolineato che le azioni possono essere asincrone, mentre le mutazioni in genere non lo sono. Puoi decidere di vedere la distinzione come un'indicazione che le mutazioni dovrebbero essere usate per qualsiasi cosa sincrona (e azioni per qualsiasi cosa asincrona); tuttavia, potresti incontrare alcune difficoltà se, ad esempio, avessi bisogno di commettere più di una mutazione (in modo sincrono) o se avessi bisogno di lavorare con un Getter delle tue mutazioni, poiché le funzioni di mutazione non ricevono né Getter né Mutazioni come argomenti ...

... il che porta a una domanda interessante.

Perché le mutazioni non ricevono Getter?

Non ho ancora trovato una risposta soddisfacente a questa domanda. Ho visto alcune spiegazioni da parte del core team che ho trovato discutibile nella migliore delle ipotesi. Se riassumo il loro utilizzo, i Getter devono essere calcolati (e spesso memorizzati nella cache) estensioni allo stato. In altre parole, sono fondamentalmente ancora lo stato, anche se richiede un certo calcolo iniziale e sono normalmente di sola lettura. Questo è almeno il modo in cui sono incoraggiati ad essere utilizzati.

Pertanto, impedire alle mutazioni di accedere direttamente a Getter significa che una delle tre cose è ora necessaria, se abbiamo bisogno di accedere al primo alcune funzionalità offerte dal secondo: (1) i calcoli di stato forniti dal Getter sono duplicati da qualche parte accessibile alla Mutazione (cattivo odore), o (2) il valore calcolato (o il relativo Getter stesso) viene tramandato come argomento esplicito alla Mutazione (funky), oppure (3) la stessa logica del Getter viene duplicata direttamente all'interno della Mutazione , senza l'ulteriore vantaggio della memorizzazione nella cache fornita dal Getter (puzza).

Di seguito è riportato un esempio di (2), che nella maggior parte degli scenari che ho riscontrato sembra l'opzione "meno male".

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 
        }
    }
}

Per me, quanto sopra sembra non solo un po 'contorto, ma anche un po' "permeabile", poiché parte del codice presente nell'Azione sta chiaramente trasudando dalla logica interna della Mutazione.

Secondo me, questa è un'indicazione di un compromesso. Credo che consentire alle mutazioni di ricevere automaticamente Getters presenti alcune sfide. Può essere sia per la progettazione di Vuex stesso, sia per gli strumenti (vue-devtools et al), o per mantenere una certa compatibilità con le versioni precedenti o una combinazione di tutte le possibilità dichiarate.

Quello che non credo è che passare Getter alle tue Mutazioni tu sia necessariamente un segno che stai facendo qualcosa di sbagliato. Lo vedo semplicemente come "rattoppare" uno dei difetti del framework.


1
Per me questa è la risposta migliore. Solo dopo averlo letto, ho avuto questo "clic" che senti quando senti di aver capito qualcosa.
Robert Kusznier,

I getter sono essenzialmente prodotti computed. Sono di sola lettura. Un modo migliore per visualizzare le mutazioni potrebbe essere quello di rimuovere ciò if elseche hai. I documenti di Vuex dicono che puoi ospitare più di 1 commitall'interno di un'azione. Quindi sarebbe logico supporre che potresti commettere una certa mutazione a seconda della logica. Considero le azioni come un modo per dettare QUALE mutazione al fuoco.
Tamb

@Tamb: State e Getters offrono entrambi dati contestuali. Ha senso che vengano interrogati prima di decidere come modificare lo Stato. Quando tali informazioni possono essere recuperate interamente dallo Stato, ha senso che l'intera logica sia incapsulata all'interno di una singola Mutazione, poiché ha accesso allo Stato. Questa è la procedura operativa standard per un setter. Ciò che ha meno senso è avere un approccio radicalmente diverso semplicemente perché ora dobbiamo interrogare un Getter per informazioni simili.
Michael Ekoka,

@Tamb: Quello che stai suggerendo è che quando abbiamo bisogno di interrogare Getters dovremmo cambiare il modello sopra e spostare la logica di selezione in un'azione proxy che può accedere al Getter e incollare insieme un mucchio di piccole mutazioni stupide. Funziona, ma è ancora tortuoso e non affronta il cattivo odore a cui mi riferisco nella mia risposta, lo sposta solo altrove.
Michael Ekoka,

I documenti dicono che per utilizzare i getter quando è necessario calcolare lo stato. Quindi è sembrato corretto oggi sono simili alle proprietà calcolate. Idk cosa stai ottenendo dicendo che l'azione può incollare mutazioni. I documenti affermano chiaramente di inserire la logica aziendale all'interno delle azioni.
Tamb

15

Penso che la risposta a TLDR sia che le mutazioni debbano essere sincrone / transazionali. Quindi, se è necessario eseguire una chiamata Ajax o eseguire qualsiasi altro codice asincrono, è necessario farlo in un'azione e quindi eseguire una mutazione dopo, per impostare il nuovo stato.


1
Questo sembra un riassunto della documentazione; con cui non c'è nulla di sbagliato. Tuttavia, il problema con questa risposta è che ciò che afferma non è necessariamente vero. È possibile modificare lo stato all'interno di una mutazione quando si richiama una funzione asincrona / AJAX, che può quindi essere modificata nel callback completo. Penso che questo sia ciò che sta causando tanta confusione sul perché le azioni dovrebbero essere usate per le migliori pratiche di sviluppo quando si lavora con Vuex. So che è stata sicuramente una fonte di confusione per me quando ho iniziato a lavorare con Vuex.
Erutan409,

8

Le principali differenze tra azioni e mutazioni:

  1. All'interno delle azioni è possibile eseguire codice asincrono ma non in mutazioni. Quindi usa le azioni per il codice asincrono altrimenti usa le mutazioni.
  2. All'interno delle azioni è possibile accedere a getter, stato, mutazioni (commetterle), azioni (inviarle) in mutazioni a cui è possibile accedere allo stato. Quindi, se vuoi accedere solo allo stato, usa le mutazioni, altrimenti usa le azioni.

5

Secondo il docs

Le azioni sono simili alle mutazioni , con le differenze che:

  • Invece di mutare lo stato, le azioni commettono mutazioni.
  • Le azioni possono contenere operazioni asincrone arbitrarie .

Considera il seguente frammento.

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.
    }
  }
})

I gestori di azioni ( incremento ) ricevono un oggetto di contesto che espone la stessa serie di metodi / proprietà sull'istanza del negozio, quindi è possibile chiamare context.commit per eseguire il commit di una mutazione o accedere allo stato e ai getter tramite context.state e context.getters


1
è la chiamata posible dalla funzione 'mutazione', un metodo dal componente vuejs?
Alberto Acuña,

@ AlbertoAcuña Ho la stessa domanda, perché quando provo a farlo, genera un errore che la mutazione locale non è definita.
Rutwick Gangurde,

5

Dichiarazione di non responsabilità - Ho appena iniziato a utilizzare vuejs, quindi sono solo io a estrapolare l'intento progettuale.

Il debug di Time Machine utilizza snapshot dello stato e mostra una sequenza temporale di azioni e mutazioni. In teoria avremmo potuto avere a actionsfianco una registrazione di setter e getter di stato per descrivere in modo sincrono la mutazione. Ma allora:

  • Avremmo input impuri (risultati asincroni) che hanno causato setter e getter. Ciò sarebbe difficile da seguire logicamente e diversi setter e getter asincroni potrebbero interagire in modo sorprendente. Questo può ancora succederemutations transazioni, ma poi possiamo dire che la transazione deve essere migliorata anziché essere una condizione di competizione nelle azioni. Le mutazioni anonime all'interno di un'azione potrebbero riaffiorare più facilmente questo tipo di bug perché la programmazione asincrona è fragile e difficile.
  • Il registro delle transazioni sarebbe difficile da leggere perché non ci sarebbe un nome per le modifiche di stato. Sarebbe molto più simile a un codice e meno inglese, privo dei raggruppamenti logici di mutazioni.
  • Potrebbe essere più complicato e meno performante lo strumento che registra qualsiasi mutazione su un oggetto dati, al contrario di adesso dove ci sono punti diff definiti in modo sincrono - prima e dopo la chiamata della funzione di mutazione. Non sono sicuro di quanto sia grande il problema.

Confrontare il seguente registro delle transazioni con le mutazioni denominate.

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

Con un registro delle transazioni che non ha mutazioni nominate:

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

Spero che tu possa estrapolare da quell'esempio la potenziale complessità aggiunta nella mutazione asincrona e anonima all'interno delle azioni.

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

Ora immagina di eseguire il debug dell'app e di esaminare i log delle mutazioni di devtool. Per ogni mutazione registrata, devtool dovrà acquisire istantanee "prima" e "dopo" dello stato. Tuttavia, il callback asincrono all'interno della mutazione di esempio sopra lo rende impossibile: il callback non è ancora chiamato quando viene commessa la mutazione, e non c'è modo per devtool di sapere quando il callback sarà effettivamente chiamato - qualsiasi mutazione di stato eseguita nel callback è essenzialmente non tracciabile!


4

mutazioni:

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

Azioni:

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

In Redux Way

Mutations are Reducers
Actions are Actions

Perché entrambi ??

Quando l'applicazione cresce, la codifica e le linee aumenteranno, quella volta che devi gestire la logica in Azioni non nelle mutazioni perché le mutazioni sono l'unica autorità per cambiare lo stato, dovrebbe essere il più pulito possibile.


2

Anche questo mi ha confuso, quindi ho fatto una semplice demo.

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;

Dopo aver studiato questo, la conclusione a cui sono giunto è che le mutazioni sono una convenzione focalizzata solo sulla modifica dei dati per separare meglio le preoccupazioni e migliorare la registrazione prima e dopo i dati aggiornati. Considerando che le azioni sono uno strato di astrazione che gestisce la logica di livello superiore e quindi chiama le mutazioni in modo appropriato


0

1.Dagli documenti :

Le azioni sono simili alle mutazioni, con le differenze che:

  • Invece di mutare lo stato, le azioni commettono mutazioni.
  • Le azioni possono contenere operazioni asincrone arbitrarie.

Le azioni possono contenere operazioni asincrone, ma la mutazione non può.

2. Richiamiamo la mutazione, possiamo cambiare direttamente lo stato. e possiamo anche nell'azione cambiare gli stati in questo modo:

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

le azioni sono progettate per gestire più altre cose, possiamo fare molte cose lì dentro (possiamo usare operazioni asincrone) quindi cambiare stato mediante mutazione di invio lì.


0

Perché non c'è stato senza mutazioni! Quando commesso - viene eseguito un pezzo di logica, che cambia lo stato in modo prevedibile. Le mutazioni sono l'unico modo per impostare o cambiare lo stato (quindi non ci sono cambiamenti diretti!) E inoltre - devono essere sincrone. Questa soluzione guida una funzionalità molto importante: le mutazioni si stanno registrando in devtools. E questo ti offre una grande leggibilità e prevedibilità!

Un'altra cosa: le azioni. Come è stato detto - le azioni commettono mutazioni. Quindi non cambiano il negozio e non è necessario che siano sincroni. Ma possono gestire un ulteriore pezzo di logica asincrona!


0

Potrebbe non essere necessario disporre di un ulteriore livello actionsper chiamare mutations, ad esempio:

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

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

Quindi se chiamate actionschiamate logout, perché non chiamare la mutazione stessa?

L'intera idea di un'azione è quella di chiamare più mutazioni dall'interno di un'azione o effettuare una richiesta Ajax o qualsiasi tipo di logica asincrona che si possa immaginare.

Alla fine potremmo avere azioni che fanno più richieste di rete e alla fine chiamano molte mutazioni diverse.

Quindi cerchiamo di roba tanto la complessità del nostro Vuex.Store()tempo possibile nelle nostre actionse questo lascia il nostro mutations, statee getterspiù pulito e semplice e è in linea con il tipo di modularità che rende librerie come Vue e reagire popolare.


0

Uso Vuex in modo professionale da circa 3 anni, ed ecco cosa penso di aver capito le differenze essenziali tra azioni e mutazioni, come puoi trarre vantaggio dall'usarli bene insieme e come puoi rendere la tua vita più difficile se non usarlo bene.

L'obiettivo principale di Vuex è offrire un nuovo modello per controllare il comportamento dell'applicazione: Reattività. L'idea è scaricare l'orchestrazione dello stato dell'applicazione su un oggetto specializzato: un negozio. Fornisce comodamente metodi per connettere i componenti direttamente ai dati del negozio da utilizzare a loro piacimento. Ciò consente ai componenti di concentrarsi sul proprio lavoro: definizione di un modello, stile e comportamento dei componenti di base da presentare all'utente. Nel frattempo, l'archivio gestisce il pesante carico di dati.

Questo non è solo l'unico vantaggio di questo modello. Il fatto che i negozi siano una singola fonte di dati per l'intera applicazione offre un grande potenziale di riusabilità di questi dati attraverso molti componenti. Questo non è il primo modello che tenta di affrontare questo problema della comunicazione tra i componenti, ma dove brilla è che ti costringe a implementare un comportamento molto sicuro per la tua applicazione vietando sostanzialmente ai tuoi componenti di modificare lo stato di questi dati condivisi e forzarlo invece a utilizzare "endpoint pubblici" per chiedere la modifica.

L'idea di base è questa:

  • Il negozio ha uno stato interno, al quale non dovrebbero mai accedere direttamente i componenti (mapState è effettivamente bandito)
  • Il negozio ha mutazioni, che sono modifiche sincrone allo stato interno. L'unico lavoro di una mutazione è quello di modificare lo stato. Dovrebbero essere chiamati solo da un'azione. Dovrebbero essere nominati per descrivere le cose che sono successe allo stato (ORDER_CANCELED, ORDER_CREATED). Tienili brevi e dolci. Puoi esaminarli utilizzando l'estensione del browser Vue Devtools (è ottimo anche per il debug!)
  • Il negozio ha anche azioni, che dovrebbero essere asincrone o restituire una promessa. Sono le azioni che i componenti chiameranno quando vorranno modificare lo stato dell'applicazione. Dovrebbero essere nominati con azioni orientate al business (verbi, ad esempio cancelOrder, createOrder). Qui è dove convalidi e invii le tue richieste. Ogni azione può chiamare diversi commit in fasi diverse se è necessario cambiare lo stato.
  • Infine, il negozio ha getter, che sono ciò che usi per esporre il tuo stato ai tuoi componenti. Aspettatevi che vengano utilizzati pesantemente su molti componenti man mano che l'applicazione si espande. Vuex memorizza le cache in modo pesante per evitare cicli di calcolo inutili (purché non si aggiungano parametri al proprio getter - cercare di non utilizzare i parametri), quindi non esitate a usarli ampiamente. Assicurati solo di dare nomi che descrivano il più vicino possibile in quale stato si trova attualmente l'applicazione.

Detto questo, la magia inizia quando iniziamo a progettare la nostra applicazione in questo modo. Per esempio:

  • Abbiamo un componente che offre un elenco di ordini all'utente con la possibilità di eliminarli
  • I componenti hanno mappato un archivio getter (deletableOrders), che è una matrice di oggetti con ID
  • Il componente ha un pulsante su ogni riga di ordini e il suo clic è associato a un'azione del negozio (deleteOrder) che gli passa l'oggetto ordine (che, ricorderemo, proviene dall'elenco del negozio stesso)
  • L'azione store deleteOrder procede come segue:
    • convalida la cancellazione
    • memorizza l'ordine da eliminare temporaneamente
    • esegue il commit della mutazione ORDER_DELETED con l'ordine
    • invia la chiamata API per eliminare effettivamente l'ordine (sì, DOPO aver modificato lo stato!)
    • attende la fine della chiamata (lo stato è già aggiornato) e in caso di errore, chiamiamo la mutazione ORDER_DELETE_FAILED con l'ordine che abbiamo conservato in precedenza.
  • La mutazione ORDER_DELETED rimuoverà semplicemente l'ordine dato dall'elenco di ordini eliminabili (che aggiornerà il getter)
  • La mutazione ORDER_DELETE_FAILED semplicemente la ripristina e modifica per dichiarare di notificare l'errore (un altro componente, notifica di errore, sta monitorando quello stato per sapere quando visualizzarsi)

Alla fine, abbiamo un'esperienza utente considerata "reattiva". Dal punto di vista del nostro utente, l'articolo è stato eliminato immediatamente. Il più delle volte, ci aspettiamo che i nostri endpoint funzionino, quindi questo è perfetto. Quando fallisce, abbiamo ancora un certo controllo su come reagirà la nostra applicazione , perché abbiamo separato con successo la preoccupazione dello stato della nostra applicazione front-end, con i dati effettivi.

Non hai sempre bisogno di un negozio, intendiamoci. Se scopri che stai scrivendo negozi che assomigliano a questo:

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
  }
}

A me sembra che tu stia usando l'archivio solo come archivio dati e forse stai perdendo l'aspetto della reattività di esso, non lasciandolo prendere anche il controllo delle variabili a cui l'applicazione reagisce. Fondamentalmente, puoi e probabilmente scarichi alcune righe di codice scritte nei tuoi componenti nei tuoi negozi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.