← Назад к вопросам

В чем разница между action и mutation?

2.0 Middle🔥 111 комментариев
#State Management

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между Action и Mutation в Vuex

Mutation и Action — это два способа изменения состояния в Vuex (state management для Vue.js). Часто начинающие разработчики путают их, но их различия критичны для правильной архитектуры.

Mutation: Синхронное изменение состояния

Mutation — это единственный способ синхронно изменить состояние в Vuex:

const mutations = {
  SET_USER(state, user) {
    state.user = user;
  },
  
  INCREMENT_COUNTER(state, amount) {
    state.counter += amount;
  },
  
  ADD_TODO(state, todo) {
    state.todos.push(todo);
  }
};

Особенности:

  • Синхронны — выполняются мгновенно
  • Принимают состояние первым параметром — state
  • Должны быть чистыми функциями — не делать асинхронные операции
  • Трассируются Dev Tools — каждое изменение видно в Vue DevTools

Action: Асинхронные операции и бизнес-логика

Action — это способ выполнить асинхронный код и затем вызвать mutation:

const actions = {
  async fetchUser({ commit }, userId) {
    try {
      const response = await fetch(`/api/users/${userId}`);
      const user = await response.json();
      
      // Вызываем mutation для обновления состояния
      commit('SET_USER', user);
    } catch (error) {
      commit('SET_ERROR', error.message);
    }
  },
  
  async createTodo({ commit }, todoData) {
    try {
      const response = await api.post('/todos', todoData);
      commit('ADD_TODO', response.data);
    } catch (error) {
      commit('SET_ERROR', error);
    }
  }
};

Особенности:

  • Асинхронны — могут выполнять API запросы, таймауты и т.д.
  • Первый параметр context — объект с { state, commit, dispatch, rootState, rootGetters }
  • Вызывают mutations — для изменения состояния
  • Могут вызывать другие actions — dispatch('otherAction')

Главная разница: Синхронность

// ПЛОХО: асинхронный код в mutation
const mutations = {
  fetchAndSetUser(state, userId) {
    // Это НАРУШЕНИЕ!
    fetch(`/api/users/${userId}`)
      .then(r => r.json())
      .then(user => state.user = user); // Dev Tools не увидит!
  }
};

// ХОРОШО: асинхронный код в action
const actions = {
  async fetchUser({ commit }, userId) {
    const response = await fetch(`/api/users/${userId}`);
    const user = await response.json();
    commit('SET_USER', user); // Трассируется
  }
};

Архитектурный паттерн

Определяется строгое разделение:

Компонент
   |
   v
dispatch(action) -> выполнить логику
   |
   v
commit(mutation) -> изменить состояние
   |
   v
Верифицируется в Dev Tools
// Компонент
export default {
  methods: {
    async loadUser() {
      // Вызываем ACTION
      await this.$store.dispatch('fetchUser', userId);
      // Затем состояние обновляется
    },
    
    handleClick() {
      // Для синхронных изменений можно прямо в mutation
      this.$store.commit('INCREMENT_COUNTER', 5);
    }
  }
};

Практические примеры

Пример 1: Загрузка данных с сервера

const store = {
  state: {
    users: [],
    loading: false,
    error: null
  },
  
  mutations: {
    SET_LOADING(state, value) {
      state.loading = value;
    },
    
    SET_USERS(state, users) {
      state.users = users;
    },
    
    SET_ERROR(state, error) {
      state.error = error;
    }
  },
  
  actions: {
    async loadUsers({ commit }) {
      commit('SET_LOADING', true);
      commit('SET_ERROR', null);
      
      try {
        const response = await fetch('/api/users');
        const users = await response.json();
        commit('SET_USERS', users);
      } catch (error) {
        commit('SET_ERROR', error.message);
      } finally {
        commit('SET_LOADING', false);
      }
    }
  }
};

Пример 2: Условная логика в action

actions: {
  // Action вызывает разные mutations в зависимости от условий
  async toggleTodo({ state, commit }, todoId) {
    const todo = state.todos.find(t => t.id === todoId);
    
    if (!todo) {
      commit('SET_ERROR', 'Todo not found');
      return;
    }
    
    try {
      await api.put(`/todos/${todoId}`, { completed: !todo.completed });
      commit('TOGGLE_TODO', todoId); // Вызываем mutation
    } catch (error) {
      commit('SET_ERROR', error.message);
    }
  }
}

Когда использовать что

Используй Mutation когда:

  • Нужно синхронно изменить состояние
  • Нет асинхронных операций
  • Изменение простое и локальное
commit('SET_THEME', 'dark');
commit('SET_COUNTER', value);
commit('TOGGLE_MODAL', true);

Используй Action когда:

  • Нужно выполнить асинхронную операцию (fetch, API)
  • Требуется условная логика перед изменением состояния
  • Нужно вызвать несколько mutations
  • Требуется обработка ошибок
dispatch('fetchUserData', userId);
dispatch('submitForm', formData);
dispatch('syncWithServer');

Сравнение в таблице

АспектMutationAction
СинхронностьТолько синхронныйМожет быть асинхронный
Параметрыstate, payloadcontext (commit, dispatch, state)
API запросыЗапрещеныРазрешены
Вызовcommitdispatch
ТрассировкаВидна в Dev ToolsВидна в Dev Tools
ИспользованиеИзменение состоянияБизнес-логика

Практический совет

Думай о разделении так:

  • Mutation — WHAT (ЧТО изменилось)
  • Action — HOW (КАК и КОГДА это изменилось)
// Action отвечает на вопрос "Как?" — делаем API запрос
actions: {
  async saveUser({ commit }, userData) {
    const savedUser = await api.post('/users', userData);
    // Mutation отвечает на вопрос "Что?" — обновляем состояние
    commit('SET_USER', savedUser);
  }
}

Это чёткое разделение делает код предсказуемым, тестируемым и отлаживаемым.

В чем разница между action и mutation? | PrepBro