← Back to all tutorials
Vuex TutorialEpisode 6

Mutations

Change state with mutations — the only way to modify store state, ensuring all changes are trackable and synchronous.

Mutations

You should never change state directly. Instead, you commit mutations — synchronous functions that are the only sanctioned way to modify state. This makes every state change trackable and debuggable.

Why Not Just Change State Directly?

// BAD — direct state manipulation
this.$store.state.products[0].price = 5;

// GOOD — commit a mutation
this.$store.commit('reducePrice', 4);

Direct changes are untraceable. Vue DevTools cannot detect them, you cannot track who changed what, and it makes debugging a nightmare. Mutations create a log of every state change.

Defining Mutations

// store/store.js
export const store = new Vuex.Store({
    state: {
        products: [
            { id: 1, name: 'Banana Skin', price: 20 },
            { id: 2, name: 'Shiny Star', price: 40 },
            { id: 3, name: 'Green Shells', price: 60 },
            { id: 4, name: 'Red Shells', price: 80 },
            { id: 5, name: 'Mushroom', price: 15 }
        ]
    },
    mutations: {
        reducePrice(state, amount) {
            state.products.forEach(product => {
                product.price -= amount;
            });
        }
    }
});

Each mutation receives state as the first argument and an optional payload as the second argument. The payload can be a number, string, or object.

Committing Mutations from Components

<template>
    <div>
        <button @click="reducePrice">Reduce Prices by $4</button>
    </div>
</template>

<script>
export default {
    methods: {
        reducePrice() {
            this.$store.commit('reducePrice', 4);
        }
    }
};
</script>

this.$store.commit('mutationName', payload) calls the mutation. The store updates, getters recompute, and all components that read from the affected state re-render.

Object-Style Commit

// Payload as an object
this.$store.commit({
    type: 'reducePrice',
    amount: 4
});

// In the mutation:
mutations: {
    reducePrice(state, payload) {
        state.products.forEach(p => {
            p.price -= payload.amount;
        });
    }
}

Rules of Mutations

RuleReason
Must be synchronousDevTools tracks mutations — async breaks the timeline
Should be the only way to change stateCreates a traceable log of all state changes
Receive state and an optional payloadState is what you modify; payload is the data needed

Key Takeaways

  • Mutations are the only way to change Vuex state — commit them with this.$store.commit()
  • They receive state and an optional payload (data to use in the change)
  • Mutations must be synchronous — for async operations, use actions (next episode)
  • Every mutation is logged by Vue DevTools for time-travel debugging