5

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.

Inigo
  • 8,110
  • 18
  • 62
  • 110

1 Answers1

7

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

GeorgesA
  • 320
  • 2
  • 9
  • 1
    This is very comprehensive; that's cleared it up- thanks! – Inigo Dec 20 '19 at 14:06
  • If this answer (https://stackoverflow.com/a/53017593/529187) is correct, the last line should not be "never do this". In many simple cases, you do not need "the ability to implement time-travel debugging, undo/redo..." – Devs love ZenUML Jun 21 '20 at 12:50
  • I was trying to point out that the documented practice is to mutate the state within mutations. If the case is simple you also might not need actions and can rely directly on mutations. – GeorgesA Jul 01 '20 at 00:44