State, Getters, Mutations & Actions
Store Structure
import { createStore } from 'vuex';
const store = createStore({
state() {
return { todos: [], loading: false };
},
getters: {
// Cached like a computed property — recomputes only when todos changes
completedTodos: (state) => state.todos.filter((t) => t.completed),
},
mutations: {
// MUST be synchronous — devtools relies on a clean before/after
// snapshot per mutation for time-travel debugging
ADD_TODO(state, todo) {
state.todos.push(todo);
},
SET_LOADING(state, value) {
state.loading = value;
},
},
actions: {
// Async work lives here; the actual state change is still a
// synchronous mutation — actions never mutate state directly
async fetchTodos({ commit }) {
commit('SET_LOADING', true);
const todos = await api.getTodos();
todos.forEach((todo) => commit('ADD_TODO', todo));
commit('SET_LOADING', false);
},
},
});Using the Store in Components
export default {
computed: {
// Reading state — direct access or the mapState helper
todos() { return this.$store.state.todos; },
},
methods: {
addTodo(text) {
// commit -> mutations (sync), dispatch -> actions (can be async)
this.$store.commit('ADD_TODO', { text, completed: false });
},
loadTodos() {
this.$store.dispatch('fetchTodos');
},
},
};
// Helper mapping shorthand
import { mapState, mapActions } from 'vuex';
export default {
computed: { ...mapState(['todos', 'loading']) },
methods: { ...mapActions(['fetchTodos']) },
};
// NEVER mutate state directly from a component — bypasses tracking
// entirely; store.state.todos.push(x) breaks devtools history and
// throws in strict mode.Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free