Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Direct manipulation of state within a Vuex action vs. using 'commit' and 'getters'

Tags:

vue.js

vuex

I understand that it is generally bad practice to manipulate the Vuex state directly from outside of the store (e.g from a component); but I'm strugging to understand what is best practice to read/change the state from within an action.

I understand that actions inherently have a context object as an argument, from which you can get the state, as well as getters, commit, and dispatch as properties. But I'm confused as to what is the best practice for using these. For example:

      testAction: ({commit, getters, state}) => {

        if(state.foo === 'bar'){ // is this bad practice? 
            // ...do a thing
        }
        if(getters.getFoo === 'bar'){ // should I always read the state with a getter like this instead?
            // ...do a thing
        }

        commit('setFoo', 'foobar'); // do I always need to set the state via commit like this

        state.foo = 'foobar' // or is it fine to just do this?

      }

Please see the comments. What is the 'correct' way to manipulate state within an action? Do I always need to use commit and getters? And if so, why does the context object even expose state; when would you ever use this in an action? Thanks.

like image 330
Inigo Avatar asked Dec 20 '19 12:12

Inigo


People also ask

What is commit in Vuex action?

commit('increment') } } }) Action handlers receive a context object which exposes the same set of methods/properties on the store instance, so you can call context. commit to commit a mutation, or access the state and getters via context.

What is the difference between mutations and actions in Vuex?

Mutations are intended to receive input only via their payload and to not produce side effects elsewhere. While actions get a full context to work with, mutations only have the state and the payload .

What is difference between dispatch and commit in Vuex?

Dispatch triggers an action whereas commit triggers a mutation. $dispatch is always used from your methods in routes/components. It sends a message to Vuex store to perform some action. The action can be performed any time after the current tick so that it will not affect the frontend performance.

How do you mutate Vuex state?

Vuex stores are reactive. When Vue components retrieve state from it, they will reactively and efficiently update if the store's state changes. You cannot directly mutate the store's state. The only way to change a store's state is by explicitly committing mutations.


1 Answers

By looking at the documentation mutations and actions are defined as such:

Actions Actions are similar to mutations, the differences being that: Instead of mutating the state, actions commit mutations. Actions can contain arbitrary asynchronous operations.

Mutations The only way to actually change state in a Vuex store is by committing a mutation. Vuex mutations are very similar to events: each mutation has a string type and a handler. The handler function is where we perform actual state modifications, and it will receive the state as the first argument: (...) One important rule to remember is that mutation handler functions must be synchronous

It is imperative that state modifications are done using mutations, else the updates wont be dispatched properly through the Vue app and the components won't update accordingly. But you are not forced to use actions to commit mutations. You could think of actions as a composition of mutations that allow you to handle complex changes to your state and asynchronous methods. So, if your action is simple enough use a mutation, else use an action. Although, be aware that as mutations are synchronous, they may freeze your front-end until the requested action is over, if the action is a heavy one (nice explication of Akryum, vuejs core member here).

In a similar manner the getters are a way of "formatting" data retrieved from the store, as stated in the docs:

Sometimes we may need to compute derived state based on store state, for example filtering through a list of items and counting them.

Meaning that if you just need a simple key from the state you don't need to create a getter, you can simply retrieve the info you need from the state.

Taking a look to your example:

testAction: ({commit, getters, state}, testData) => {

    if(state.foo === 'bar'){ // is this bad practice? ==> Good to go !
        // ...do a thing
    }

    if(getters.getFoo === 'bar'){ // should I always read the state with a getter like this instead?  ==> Good to go ! but it depends on the way you can retrieve data from the state (like if you need to know the number of items within a list)
        // ...do a thing
    }

    commit('setFoo', 'testData'); // do I always need to set the state via commit like this  ==> **YES** !

    state.foo = 'foobar' // or is it fine to just do this? ==> never do this

}

Also for an easier integration of VueX in your components, the api exposes a set of functions to access the store properties and use them as computed properties or methods: mapActions, mapMutations, mapGetters and mapState

like image 112
GeorgesA Avatar answered Sep 17 '22 19:09

GeorgesA