iartist93
iartist93

Reputation: 335

Mutate Vuex state directly without using mutations

I'm coming for react/redux to vue and while learning vuex I found that I can directly mutate the state and the state changes still reflects on the other components that use it.

This behavior is forbidden in Redux if I mutate the state directly other components won't get notified about those changes, so we must use actions and reducers for this.

All those methods basically provide the same result.

methods: {
    IncrementDirect () {
      // mutates the state directly
      this.$store.state.counter += 2;
    },
    incrementDispatch() {
      // mutates the state inside actions
      this.$store.dispatch("handleIncrement", 2);
    },
    incrementCommit() {
      // mutates the state inside mutations
      this.$store.commit("increment", 2);
    },
  },

My question is why this behavior is allowed, and why we have to use mutations if we can literally mutate the state anywhere in the app.

Upvotes: 2

Views: 1448

Answers (3)

NatanS
NatanS

Reputation: 86

I think that the behavior might have changed and reactivity still works without requiring the use mutations.

I was unable to find clear evidence though.

With the rather recent introduction of reactivity and proxy objects (which Vuex4/Vue3 take advantage of), it sounds like a rather simple task to have the "commit" code inside the handler setter function. I believe that's what they ended up doing, the closest thing to an explanation I have found is pinia.

I am pretty sure that in Vue2/Vuex3, updating the state directly would have failed.

Upvotes: 1

Haron
Haron

Reputation: 2629

Actions are asynchronous where mutations are not

export default new Vuex.Store({
  state: {
    // put variables and collections here
  },
  mutations: {
    // put synchronous functions for changing state e.g. add, edit, delete
  },
  actions: {
    // put asynchronous functions that can call one or more mutation functions
  }
})

Make it a practice to never commit your Mutations directly. Always use Actions to commit your mutations

Related questions: Vuex Action vs Mutations, Is it bad to commit mutations without using actions in Vuex?, Direct manipulation of state within a Vuex action vs. using 'commit' and 'getters'

Upvotes: -1

Nathan Strutz
Nathan Strutz

Reputation: 8123

Something that differs from Redux to Vuex is that state changes don't create a new state. Vue feigns immutability, but for performance, actually mutates the state and tracks the mutations through reactive channels. It's a neat trick, but as you've discovered, has some mild side-effects.

When you change the state directly, like through a component or from an action, you aren't using those official mutation channels. I've debugged code where it look like this works, but then found bugs later because the reactivity didn't kick in all the way and updates weren't happening.

It should also be mentioned that debugging Vuex through the Vue dev tools, which is really handy, won't show you any state changes unless you use mutations. Also if you have any Vuex plugins, they won't execute unless there's a mutation.

Beyond all of these technical reasons, which may seem sort of vague, I feel the need to point out how this is absolutely not the way of the flux framework for state changes. Coming from the React world, you know that state changes should happen in a big circle; In Redux, components call actions, which call a reducer to return a new state, which is then applied and the app is re-rendered and ready for another change from the component. The framework forces that order to decouple the UI from the state (though I would argue that this isn't a good idea) and to make sure all state changes happen in one place. The same is true with Vuex mutations - this is where all state changes should happen.

Pushing past this as the current state (pun not intended) of things, it should be noted that you can do some very interesting things in Vue 3. One of them is that you can make a reactive object outside of your Vue components, import that object into your components as the global state, and mutate it all you like. Vue 3 will keep those mutations in sync with the whole application, and with some planning, it could make for a very capable Vuex replacement.

Hot on the heels of that, the next Vuex looks like it may be ditching the concept of separate mutations, and could have all your state change directly through actions or something else. I bet it will use the Vue 3 reactivity system as described above, with Vuex's thoughts on module organization to make a very simple framework.

All that to say, your intuitions are correct for the way forward, but may be premature for today.

Upvotes: 3

Related Questions