Vuex Action vs Mutations

173

En Vuex, ¿cuál es la lógica de tener tanto "acciones" como "mutaciones"?

Entiendo la lógica de los componentes que no pueden modificar el estado (lo que parece inteligente), pero tener ambas acciones y mutaciones parece que está escribiendo una función para activar otra función, para luego alterar el estado.

¿Cuál es la diferencia entre "acciones" y "mutaciones", cómo funcionan juntas, y más aún, tengo curiosidad por qué los desarrolladores de Vuex decidieron hacerlo de esta manera?

Kobi
fuente
2
Ver "On To Actions", creo: vuex.vuejs.org/en/mutations.html#on-to-actions
Roy J
discusión relacionada: github.com/vuejs/vuex/issues/587
chuck911
1
No puede mutar directamente el estado de la tienda. La única forma de cambiar el estado de una tienda es mediante la confirmación explícita de mutaciones. Para eso necesitamos acciones para cometer mutaciones.
Suresh Sapkota
1
@SureshSapkota que la declaración es muy confuso, ya que tanto mutationsy actionsse definted en la documentación vuex como métodos para cambiar el estado. No necesitas una acción para cometer una mutación.
Graham
1
Las mutaciones, como su nombre indica, se utilizan para modificar / mutar su objeto de estado. Las acciones son bastante similares a las mutaciones, pero en lugar de mutar el estado, las acciones cometen mutaciones. Las acciones pueden contener cualquier código asíncrono arbitrario o lógica empresarial . Vuex recomienda que el objeto de estado solo se mute dentro de las funciones de mutación. También se recomienda no ejecutar ningún código pesado o de bloqueo dentro de las funciones de mutación, ya que es de naturaleza sincrónica .
Emmanuel Neni

Respuestas:

221

Pregunta 1 : ¿Por qué los desarrolladores de Vuejs decidieron hacerlo de esta manera?

Responder:

  1. Cuando su aplicación se vuelve grande, y cuando hay múltiples desarrolladores trabajando en este proyecto, encontrará que la "gestión de estado" (especialmente el "estado global") se volverá cada vez más complicada.
  2. La forma vuex (al igual que Redux en react.js ) ofrece un nuevo mecanismo para administrar el estado, mantener el estado y "guardar y rastrear" (eso significa que cada acción que modifica el estado puede ser rastreada por la herramienta de depuración: vue-devtools )

Pregunta 2 : ¿Cuál es la diferencia entre "acción" y "mutación"?

Veamos primero la explicación oficial:

Mutaciones:

Las mutaciones de Vuex son esencialmente eventos: cada mutación tiene un nombre y un controlador.

import Vuex from 'vuex'

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

Acciones: las acciones son solo funciones que despachan mutaciones.

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

Aquí está mi explicación de lo anterior:

  • la mutación es la única forma de modificar el estado
  • la mutación no se preocupa por la lógica de negocios, solo se preocupa por el "estado"
  • la acción es lógica de negocios
  • La acción puede enviar más de 1 mutación a la vez, solo implementa la lógica de negocios, no le importa el cambio de datos (que se administran por mutación)
Kaicui
fuente
80
Es útil el hecho de que una acción "es la lógica de negocios" y puede despachar múltiples mutaciones a la vez. Esa es la respuesta que estaba buscando. Gracias.
Kobi
11
ustedes están diciendo que "despachan una mutación". ¿No es la redacción correcta que cometes una mutación?
ProblemsOfSumit
44
Despacha acciones y comete mutaciones.
eirik
44
el despacho ya no funciona en vue 2.0 para la mutación, debe cometer una mutación en la acción.
SKLTFZ
18
@Kaicui A esta respuesta le falta una nota sobre las mutaciones siempre sincrónicas y las acciones potencialmente asincrónicas. Aparte de eso, una buena respuesta!
decae el
58

Las mutaciones son sincrónicas, mientras que las acciones pueden ser asincrónicas.

Para decirlo de otra manera: no necesita acciones si sus operaciones son sincrónicas; de lo contrario, impleméntelas.

Bas
fuente
2
Esto realmente responde una pregunta que iba a hacer, sobre cómo el ejemplo de todomvc no hace uso de acciones.
sksallaj
77
'No necesita acciones si sus operaciones son sincrónicas' : Eso no es cierto: necesita acciones si desea componer múltiples mutaciones del mismo módulo, porque no puede llamar a otra acción desde una acción.
Raymundus el
1
El seguimiento obvio de esta respuesta sería "entonces, ¿por qué no simplemente tener acciones y deshacerse de las mutaciones?"
Michael Mrozek
34

Creo que tener una comprensión de las motivaciones detrás de las mutaciones y las acciones le permite a uno juzgar mejor cuándo usar qué y cómo. También libera al programador de la carga de la incertidumbre en situaciones donde las "reglas" se vuelven confusas. Después de razonar un poco sobre sus respectivos propósitos, llegué a la conclusión de que, aunque definitivamente puede haber formas incorrectas de usar acciones y mutaciones, no creo que haya un enfoque canónico.

Primero intentemos entender por qué incluso pasamos por Mutaciones o Acciones.

¿Por qué pasar por la repetitiva en primer lugar? ¿Por qué no cambiar el estado directamente en los componentes?

Estrictamente hablando, puede cambiar statedirectamente desde sus componentes. El statees sólo un objeto de JavaScript y no hay nada mágico que revertir los cambios que realice en ella.

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

Sin embargo, al hacer esto, está dispersando sus mutaciones de estado por todo el lugar. Pierde la capacidad de simplemente abrir un solo módulo que aloja el estado y de un vistazo ver qué tipo de operaciones se pueden aplicar a él. Tener mutaciones centralizadas resuelve esto, aunque a costa de algunas repeticiones.

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

Creo que si reemplaza algo corto con repetitivo, querrá que el repetitivo también sea pequeño. Por lo tanto, supongo que las mutaciones están destinadas a ser envoltorios muy delgados alrededor de las operaciones nativas en el estado, casi sin lógica comercial. En otras palabras, las mutaciones están destinadas a ser utilizadas principalmente como setters.

Ahora que ha centralizado sus mutaciones, tiene una mejor visión general de sus cambios de estado y, dado que sus herramientas (vue-devtools) también conocen esa ubicación, facilita la depuración. También vale la pena tener en cuenta que muchos complementos de Vuex no miran el estado directamente para rastrear los cambios, sino que dependen de mutaciones para eso. Los cambios "fuera de límite" al estado son invisibles para ellos.

Entonces mutations, actions¿cuál es la diferencia de todos modos?

Las acciones, como las mutaciones, también residen en el módulo de la tienda y pueden recibir el stateobjeto. Lo que implica que también podrían mutarlo directamente. Entonces, ¿qué sentido tiene tener ambos? Si razonamos que las mutaciones tienen que mantenerse pequeñas y simples, implica que necesitamos un medio alternativo para albergar una lógica comercial más elaborada. Las acciones son los medios para hacer esto. Y como hemos establecido anteriormente, vue-devtools y los complementos son conscientes de los cambios a través de las mutaciones, para mantener la coherencia debemos seguir usando las mutaciones de nuestras acciones. Además, dado que las acciones deben abarcar todo y que la lógica que encapsulan puede ser asíncrona, tiene sentido que las acciones también se vuelvan asincrónicas desde el principio.

A menudo se enfatiza que las acciones pueden ser asíncronas, mientras que las mutaciones generalmente no lo son. Puede decidir ver la distinción como una indicación de que las mutaciones deben usarse para cualquier cosa sincrónica (y acciones para cualquier cosa asincrónica); sin embargo, tendría algunas dificultades si, por ejemplo, necesitara cometer más de una mutación (sincrónicamente) o si necesitara trabajar con un Getter de sus mutaciones, ya que las funciones de mutación no reciben Getters ni Mutations como argumentos ...

... lo que lleva a una pregunta interesante.

¿Por qué las mutaciones no reciben Getters?

Todavía no he encontrado una respuesta satisfactoria a esta pregunta. He visto alguna explicación del equipo central de que encontré discutible en el mejor de los casos. Si resumo su uso, los Getters están destinados a ser extensiones computadas (y a menudo en caché) del estado. En otras palabras, básicamente siguen siendo el estado, aunque eso requiere un cálculo inicial y normalmente son de solo lectura. Al menos así es como se les anima a ser utilizados.

Por lo tanto, evitar que las mutaciones accedan directamente a Getters significa que ahora es necesaria una de tres cosas, si necesitamos acceder desde la primera parte de la funcionalidad ofrecida por la última: (1) los cálculos de estado proporcionados por Getter se duplican en algún lugar que sea accesible a la Mutación (mal olor), o (2) el valor calculado (o el Getter correspondiente) se transmite como un argumento explícito a la Mutación (funky), o (3) la lógica del Getter se duplica directamente dentro de la Mutación , sin el beneficio adicional de almacenamiento en caché como lo proporciona Getter (hedor).

El siguiente es un ejemplo de (2), que en la mayoría de los escenarios que he encontrado parece la opción "menos mala".

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

Para mí, lo anterior parece no solo un poco complicado, sino también algo "permeable", ya que parte del código presente en la Acción está claramente exudando de la lógica interna de la Mutación.

En mi opinión, esto es una indicación de un compromiso. Creo que permitir que Mutaciones reciba Getters automáticamente presenta algunos desafíos. Puede ser tanto para el diseño de Vuex como para las herramientas (vue-devtools et al), o para mantener cierta compatibilidad con versiones anteriores, o alguna combinación de todas las posibilidades establecidas.

Lo que no creo es que pasar Getters a tus mutaciones tú mismo sea necesariamente una señal de que estás haciendo algo mal. Lo veo simplemente como "parchear" una de las deficiencias del marco.

Michael Ekoka
fuente
1
Para mí esa es la mejor respuesta. Solo después de leerlo, tuve este "clic" que sientes cuando sientes que entendiste algo.
Robert Kusznier
Los captadores son esencialmente de computedsalida. Son de solo lectura. Una mejor manera de ver las mutaciones podría ser eliminar la if elseque tiene. Los documentos de vuex dicen que puedes alojar más de 1 commitdentro de una acción. Por lo tanto, sería lógico suponer que podría cometer cierta mutación dependiendo de la lógica. Veo las acciones como una forma de dictar QUÉ mutación disparar.
Tamb
@Tamb: State y Getters ofrecen datos contextuales. Tiene sentido que se les consulte antes de decidir cómo modificar el Estado. Cuando esa información se puede obtener completamente del Estado, tiene sentido que toda la lógica se encapsule dentro de una sola Mutación, ya que tiene acceso al Estado. Este es un procedimiento operativo estándar para un setter. Lo que tiene menos sentido es tener un enfoque radicalmente diferente simplemente porque ahora necesitamos consultar a un Getter para obtener información similar.
Michael Ekoka
@Tamb: Lo que está sugiriendo es que cuando necesitemos consultar a Getters, deberíamos cambiar el patrón anterior y mover la lógica de selección a una Acción proxy que pueda acceder al Getter y pueda unir un montón de pequeñas Mutaciones tontas. Funciona, pero sigue siendo tortuoso y no aborda el mal olor al que me refiero en mi respuesta, simplemente lo mueve a otro lado.
Michael Ekoka
Los documentos dicen que para usar getters cuando necesitas calcular el estado. Por lo tanto, parecía correcto hoy en día que son similares a las propiedades calculadas. No sé a qué te refieres al decir que la acción puede unir mutaciones. Los documentos claramente dicen que poner lógica de negocios dentro de las acciones.
Tamb
15

Creo que la respuesta TLDR es que las mutaciones están destinadas a ser sincrónicas / transaccionales. Entonces, si necesita ejecutar una llamada Ajax, o hacer cualquier otro código asincrónico, debe hacerlo en una Acción, y luego cometer una mutación después, para establecer el nuevo estado.

Noah Namey
fuente
1
Esto parece un resumen de la documentación; con lo cual no hay nada de malo. Sin embargo, el problema con esta respuesta es que lo que afirma no es necesariamente cierto. PUEDE modificar el estado dentro de una mutación al invocar una función asincrónica / AJAX, que luego puede modificarse en la devolución de llamada completa. Creo que esto es lo que está causando tanta confusión sobre por qué las acciones deberían usarse para las mejores prácticas de desarrollo cuando se trabaja con Vuex. Sé que sin duda fue una fuente de confusión para mí cuando comencé a trabajar con Vuex.
Erutan409
8

Las principales diferencias entre acciones y mutaciones:

  1. Dentro de las acciones puede ejecutar código asincrónico pero no en mutaciones. Por lo tanto, use acciones para el código asincrónico; de lo contrario, use mutaciones.
  2. Dentro de las acciones puedes acceder a getters, estados, mutaciones (cometerlos), acciones (despacharlas) en mutaciones puedes acceder al estado. Entonces, si desea acceder solo al estado, use mutaciones; de lo contrario, use acciones.
roli roli
fuente
5

De acuerdo con la docs

Las acciones son similares a las mutaciones , las diferencias son que:

  • En lugar de mutar el estado, las acciones cometen mutaciones.
  • Las acciones pueden contener operaciones asincrónicas arbitrarias .

Considere el siguiente fragmento.

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

Los manejadores de acciones ( incremento ) reciben un objeto de contexto que expone el mismo conjunto de métodos / propiedades en la instancia de la tienda, por lo que puede llamar a context.commit para confirmar una mutación o acceder al estado y a los captadores a través de context.state y context.getters

Abdullah Khan
fuente
1
¿Es posible llamar desde la función 'mutación', un método del componente vuejs?
Alberto Acuña
@ AlbertoAcuña Tengo la misma pregunta, porque cuando trato de hacer eso, arroja un error de que la mutación local no está definida.
Rutwick Gangurde
5

Descargo de responsabilidad: acabo de comenzar a usar vuejs, así que solo soy yo extrapolando la intención del diseño.

La depuración de la máquina del tiempo utiliza instantáneas del estado y muestra una línea de tiempo de acciones y mutaciones. En teoría, podríamos haber tenido actionsjunto con una grabación de establecedores de estado y captadores para describir sincrónicamente la mutación. Pero entonces:

  • Tendríamos entradas impuras (resultados asíncronos) que causaron los setters y getters. Esto sería difícil de seguir lógicamente y los configuradores y getters asíncronos diferentes pueden interactuar sorprendentemente. Eso todavía puede suceder con las mutationstransacciones, pero luego podemos decir que la transacción debe mejorarse en lugar de ser una condición de carrera en las acciones. Las mutaciones anónimas dentro de una acción podrían resurgir más fácilmente este tipo de errores porque la programación asincrónica es frágil y difícil.
  • El registro de transacciones sería difícil de leer porque no habría nombre para los cambios de estado. Sería mucho más parecido a un código y menos inglés, sin las agrupaciones lógicas de mutaciones.
  • Puede ser más complicado y menos eficaz para el instrumento registrar cualquier mutación en un objeto de datos, a diferencia de ahora donde hay puntos de diferencia definidos sincrónicamente, antes y después de la llamada a la función de mutación. No estoy seguro de qué tan grande es el problema.

Compare el siguiente registro de transacciones con mutaciones con nombre.

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

Con un registro de transacciones que no tiene mutaciones con nombre:

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

Espero que puedan extrapolar de ese ejemplo la posible complejidad añadida en la mutación asíncrona y anónima dentro de las acciones.

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

Ahora imagine que estamos depurando la aplicación y mirando los registros de mutación de la herramienta de desarrollo. Para cada mutación registrada, el devtool deberá capturar instantáneas del estado "antes" y "después". Sin embargo, la devolución de llamada asincrónica dentro de la mutación de ejemplo anterior hace que sea imposible: la devolución de llamada aún no se llama cuando se confirma la mutación, y no hay forma de que la herramienta devtool sepa cuándo se llamará realmente la devolución de llamada: cualquier mutación de estado realizada en la devolución de llamada es esencialmente no rastreable!

ubershmekel
fuente
4

Mutaciones:

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

Comportamiento:

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

En forma de Redux

Mutations are Reducers
Actions are Actions

¿Por qué ambos?

Cuando la aplicación crezca, la codificación y las líneas aumentarán, esa vez debe manejar la lógica en las acciones, no en las mutaciones porque las mutaciones son la única autoridad para cambiar el estado, debe estar lo más limpio posible.

Gopinath Kaliappan
fuente
2

Esto también me confundió, así que hice una demostración simple.

componente.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;

Después de investigar esto, la conclusión a la que llegué es que las mutaciones son una convención centrada solo en cambiar los datos para separar mejor las preocupaciones y mejorar el registro antes y después de los datos actualizados. Mientras que las acciones son una capa de abstracción que maneja la lógica de nivel superior y luego llama a las mutaciones adecuadamente

Pista de Nathaniel
fuente
0

1.De los documentos :

Las acciones son similares a las mutaciones, las diferencias son que:

  • En lugar de mutar el estado, las acciones cometen mutaciones.
  • Las acciones pueden contener operaciones asincrónicas arbitrarias.

Las acciones pueden contener operaciones asincrónicas, pero la mutación no.

2. Invocamos la mutación, podemos cambiar el estado directamente. y también podemos en la acción de cambiar estados de esta manera:

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

las Acciones están diseñadas para manejar otras cosas más, podemos hacer muchas cosas allí (podemos usar operaciones asincrónicas) y luego cambiar el estado enviando la mutación allí.

aeronave
fuente
0

¡Porque no hay estado sin mutaciones! Cuando se compromete, se ejecuta una pieza de lógica que cambia el estado de manera previsible. Las mutaciones son la única forma de establecer o cambiar el estado (por lo que no hay cambios directos) y, además, deben ser sincrónicas. Esta solución maneja una funcionalidad muy importante: las mutaciones están iniciando sesión en devtools. ¡Y eso le proporciona una gran legibilidad y previsibilidad!

Una cosa más: acciones. Como se ha dicho, las acciones cometen mutaciones. Por lo tanto, no cambian la tienda, y no hay necesidad de que estos sean sincrónicos. ¡Pero pueden manejar una pieza adicional de lógica asincrónica!

Sumit Patel
fuente
0

Puede parecer innecesario tener una capa adicional de actionssolo para llamar mutations, por ejemplo:

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

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

Entonces, si actionsllama logout, ¿por qué no llamar a la mutación en sí?

La idea completa de una acción es llamar a múltiples mutaciones desde dentro de una acción o hacer una solicitud Ajax o cualquier tipo de lógica asincrónica que puedas imaginar.

Eventualmente podríamos tener acciones que realicen múltiples solicitudes de red y eventualmente llamen a muchas mutaciones diferentes.

Así que tratamos de eliminar tanta complejidad Vuex.Store()como sea posible en nuestro actionsy esto deja nuestro mutations, stateygetters más limpio y sencillo y está en consonancia con el tipo de modularidad que hace que las bibliotecas como Vue y reaccionar popular.

Daniel
fuente
0

He estado usando Vuex profesionalmente durante aproximadamente 3 años, y esto es lo que creo que he descubierto sobre las diferencias esenciales entre acciones y mutaciones, cómo puede beneficiarse de usarlas bien juntas y cómo puede hacer su vida más difícil si No lo uses bien.

El objetivo principal de Vuex es ofrecer un nuevo patrón para controlar el comportamiento de su aplicación: la reactividad. La idea es descargar la orquestación del estado de su aplicación a un objeto especializado: una tienda. Proporciona convenientemente métodos para conectar sus componentes directamente a los datos de su tienda para usarlos a su conveniencia. Esto permite que sus componentes se centren en su trabajo: definir una plantilla, estilo y comportamiento de componentes básicos para presentar a su usuario. Mientras tanto, la tienda maneja la pesada carga de datos.

Sin embargo, esa no es solo la única ventaja de este patrón. El hecho de que las tiendas sean una sola fuente de datos para la totalidad de su aplicación ofrece un gran potencial de reutilización de estos datos en muchos componentes. Este no es el primer patrón que intenta abordar este problema de comunicación entre componentes, pero lo que destaca es que te obliga a implementar un comportamiento muy seguro en tu aplicación, básicamente prohibiendo a tus componentes modificar el estado de estos datos compartidos. y forzarlo a utilizar "puntos finales públicos" para solicitar un cambio.

La idea básica es esta:

  • La tienda tiene un estado interno, al que nunca deben acceder directamente los componentes (mapState está efectivamente prohibido)
  • La tienda tiene mutaciones, que son modificaciones sincrónicas al estado interno. El único trabajo de una mutación es modificar el estado. Solo deben llamarse desde una acción. Deben nombrarse para describir las cosas que le sucedieron al estado (ORDER_CANCELED, ORDER_CREATED). Mantenlos cortos y dulces. Puede recorrerlos utilizando la extensión del navegador Vue Devtools (¡también es excelente para la depuración!)
  • La tienda también tiene acciones, que deben ser asíncronas o devolver una promesa. Son las acciones que sus componentes llamarán cuando quieran modificar el estado de la aplicación. Deben nombrarse con acciones orientadas a los negocios. (verbos, es decir cancelOrder, createOrder). Aquí es donde valida y envía sus solicitudes. Cada acción puede invocar confirmaciones diferentes en diferentes pasos si es necesario cambiar el estado.
  • Finalmente, la tienda tiene captadores, que son los que usa para exponer su estado a sus componentes. Espere que sean muy utilizados en muchos componentes a medida que su aplicación se expande. Vuex almacena en caché los captadores en gran medida para evitar ciclos de cómputo inútiles (siempre y cuando no agregue parámetros a su captador, intente no usar parámetros), así que no dude en usarlos ampliamente. Solo asegúrese de dar nombres que describan lo más cerca posible el estado actual de la aplicación.

Dicho esto, la magia comienza cuando comenzamos a diseñar nuestra aplicación de esta manera. Por ejemplo:

  • Tenemos un componente que ofrece una lista de pedidos al usuario con la posibilidad de eliminarlos.
  • Los componentes han mapeado un captador de tienda (deletableOrders), que es una matriz de objetos con identificadores
  • El componente tiene un botón en cada fila de pedidos, y su clic se asigna a una acción de la tienda (deleteOrder) que le pasa el objeto de la orden (que, recordaremos, proviene de la lista de la tienda)
  • La acción deleteOrder de la tienda hace lo siguiente:
    • valida la eliminación
    • almacena la orden para eliminar temporalmente
    • confirma la mutación ORDER_DELETED con el pedido
    • envía la llamada API para eliminar el pedido (sí, ¡DESPUÉS de modificar el estado!)
    • espera a que finalice la llamada (el estado ya está actualizado) y, en caso de falla, llamamos a la mutación ORDER_DELETE_FAILED con el orden que mantuvimos anteriormente.
  • La mutación ORDER_DELETED simplemente eliminará el pedido dado de la lista de pedidos borrables (que actualizará el captador)
  • La mutación ORDER_DELETE_FAILED simplemente lo vuelve a colocar y modifica el estado para notificar el error (otro componente, notificación de error, rastrearía ese estado para saber cuándo mostrarse)

Al final, tenemos una experiencia de usuario que se considera "reactiva". Desde la perspectiva de nuestro usuario, el elemento se ha eliminado de inmediato. La mayoría de las veces, esperamos que nuestros puntos finales funcionen, así que esto es perfecto. Cuando falla, todavía tenemos cierto control sobre cómo reaccionará nuestra aplicación , porque hemos separado con éxito la preocupación del estado de nuestra aplicación front-end, con los datos reales.

No siempre necesitas una tienda, eso sí. Si descubre que está escribiendo tiendas que se ven así:

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

Para mí, parece que solo está usando la tienda como una tienda de datos, y tal vez se está perdiendo el aspecto de la reactividad, al no permitir que también tome el control de las variables a las que reacciona su aplicación. Básicamente, puede y probablemente deba descargar algunas líneas de código escritas en sus componentes a sus tiendas.

Alex
fuente