Spec-Zone.ru › Vuex 3

Действия

Попробуйте этот урок на Scrimba

Действия похожи на мутации, различия заключаются в том, что:

  • Вместо изменения состояния, действия производят мутации.
  • Действия могут содержать произвольные асинхронные операции.

Зарегистрируем простое действие:

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})

Обработчики действий получают объект контекста, который предоставляет тот же набор методов/свойств, что и экземпляр хранилища, поэтому вы можете вызвать context.commit для выполнения мутации или получить доступ к состоянию и геттерам через context.state и context.getters. Мы даже можем вызвать другие действия с помощью context.dispatch. Мы увидим, почему этот объект контекста не является самим экземпляром хранилища, когда введем Модули позже.

На практике мы часто используем деструктуризацию ES2015 аргументов (открывается в новой вкладке), чтобы немного упростить код (особенно когда нужно вызывать commit несколько раз):

actions: {
  increment ({ commit }) {
    commit('increment')
  }
}

Диспечирование действий

Действия вызываются с помощью метода store.dispatch.

store.dispatch('increment')

На первый взгляд это может показаться глупым: если мы хотим увеличить счётчик, почему бы не вызвать store.commit('increment') напрямую? Помните, что мутации должны быть синхронными. Действия нет. Мы можем выполнить асинхронные операции внутри действия:

actions: {
  incrementAsync ({ commit }) {
    setTimeout(() => {
      commit('increment')
    }, 1000)
  }
}

Действия поддерживают тот же формат полезной нагрузки и диспечирование в стиле объект:

// dispatch with a payload
store.dispatch('incrementAsync', {
  amount: 10
})

// dispatch with an object
store.dispatch({
  type: 'incrementAsync',
  amount: 10
})

Более практичным примером действий из реальной жизни было бы действие для оформления заказа в корзине, которое включает в себя вызов асинхронного API и выполнение нескольких мутаций:

actions: {
  checkout ({ commit, state }, products) {
    // save the items currently in the cart
    const savedCartItems = [...state.cart.added]
    // send out checkout request, and optimistically
    // clear the cart
    commit(types.CHECKOUT_REQUEST)
    // the shop API accepts a success callback and a failure callback
    shop.buyProducts(
      products,
      // handle success
      () => commit(types.CHECKOUT_SUCCESS),
      // handle failure
      () => commit(types.CHECKOUT_FAILURE, savedCartItems)
    )
  }
}

Обратите внимание, что мы выполняем поток асинхронных операций и записываем побочные эффекты (мутации состояния) действия, выполняя их.

Диспечирование действий в компонентах

Вы можете диспечить действия в компонентах с помощью this.$store.dispatch('xxx'), или использовать вспомогательную функцию mapActions, которая сопоставляет методы компонента с вызовами store.dispatch (требуется инъекция корневого store).

import { mapActions } from 'vuex'

export default {
  // ...
  methods: {
    ...mapActions([
      'increment', // map `this.increment()` to `this.$store.dispatch('increment')`

      // `mapActions` also supports payloads:
      'incrementBy' // map `this.incrementBy(amount)` to `this.$store.dispatch('incrementBy', amount)`
    ]),
    ...mapActions({
      add: 'increment' // map `this.add()` to `this.$store.dispatch('increment')`
    })
  }
}

Композиция действий

Действия часто являются асинхронными, так как мы знаем, когда действие выполнено? И что ещё важнее, как мы можем комбинировать несколько действий вместе, чтобы обрабатывать более сложные асинхронные потоки?

Первое, что нужно знать, это то, что store.dispatch может обрабатывать возвращаемое Promise от запущенного обработчика действия, и оно также возвращает Promise:

actions: {
  actionA ({ commit }) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        commit('someMutation')
        resolve()
      }, 1000)
    })
  }
}

Теперь вы можете сделать:

store.dispatch('actionA').then(() => {
  // ...
})

А также в другом действии:

actions: {
  // ...
  actionB ({ dispatch, commit }) {
    return dispatch('actionA').then(() => {
      commit('someOtherMutation')
    })
  }
}

И, наконец, если мы используем async / await (открывается в новой вкладке), мы можем комбинировать наши действия следующим образом:

// assuming `getData()` and `getOtherData()` return Promises

actions: {
  async actionA ({ commit }) {
    commit('gotData', await getData())
  },
  async actionB ({ dispatch, commit }) {
    await dispatch('actionA') // wait for `actionA` to finish
    commit('gotOtherData', await getOtherData())
  }
}

Возможна ситуация, когда store.dispatch запускает несколько обработчиков действий в разных модулях. В этом случае возвращаемое значение будет Promise, который разрешается, когда все запущенные обработчики будут разрешены.

← Мутации Модули →

© 2015–present Evan You
Licensed under the MIT License.
https://vuex.vuejs.org/guide/actions.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API