百科狗-知识改变命运!
--

action - 异步提交 mutation,dispatch() 分发 - vuex(状态管理)

乐乐1年前 (2023-11-21)阅读数 50#技术干货
文章标签函数

action

action类似于mutation,不同在于:

  • action提交的是mutation,而不是直接变更状态。
  • action可以包含任意异步操作。

让我们来注册一个简单的action:

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

action函数接受一个与store实例具有相同方法和属性的context对象,因此你可以调用context.commit提交一个mutation,或者通过context.state和context.getters来获取state和getters。

当我们在之后介绍到Modules时,你就知道context对象为什么不是store实例本身了。

实践中,我们会经常用到 ES2015 的参数解构来简化代码(特别是我们需要调用commit很多次的时候):

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


action API

actions类型: { [type: string]: Function }
在 store 上注册 action。处理函数总是接受 context 作为第一个参数,payload 作为第二个参数(可选)。

context 对象包含以下属性:

{
  state,      // 等同于 `store.state`,若在模块中则为局部状态
  rootState,  // 等同于 `store.state`,只存在于模块中
  commit,     // 等同于 `store.commit`
  dispatch,   // 等同于 `store.dispatch`
  getters,    // 等同于 `store.getters`
  rootGetters // 等同于 `store.getters`,只存在于模块中
}

所以:

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


相当于:

actions:{
  increment ({ commit: context.commit }) {
    context.commit('increment');
  }
}


相当于:

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


分发 Action

Action 通过store.dispatch方法触发:

store.dispatch('increment')

乍一眼看上去感觉多此一举,我们直接分发mutation岂不更方便?实际上并非如此,还记得mutation必须同步执行这个限制么?Action 就不受约束!我们可以在action内部执行异步操作:

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

Actions 支持同样的payload方式对象方式进行分发:

// 以payload形式分发
store.dispatch('incrementAsync', {
  amount: 10
})

// 以对象形式分发
store.dispatch({
  type: 'incrementAsync',
  amount: 10
})

来看一个更加实际的购物车示例,涉及到调用异步 API分发多重mutation:

actions: {
  checkout ({ commit, state }, products) {
    // 把当前购物车的物品备份起来
    const savedCartItems = [...state.cart.added]
    // 发出结账请求,然后乐观地清空购物车 commit(types.CHECKOUT_REQUEST)
    // 购物 API 接受一个成功回调和一个失败回调
    shop.buyProducts(
      products,
      // 成功操作
      () => commit(types.CHECKOUT_SUCCESS),
      // 失败操作
      () => commit(types.CHECKOUT_FAILURE, savedCartItems)
    )
  }
}

注意:我们正在进行一系列的异步操作,并且通过提交mutation来记录action产生的副作用(即状态变更)。


在组件中分发 Action

你在组件中使用this.$store.dispatch('xxx')分发action,或者使用mapActions()辅助函数将组件的methods映射为store.dispatch调用(需要先在根节点注入store):

import { mapActions } from 'vuex'

export default {
  // ...
  methods: {
    ...mapActions([
      'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`

      // `mapActions` 也支持载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
    ]),
    ...mapActions({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
    })
  }
}


组合 Action

Action通常是异步的,那么如何知道action什么时候结束呢?更重要的是,我们如何才能组合多个action,以处理更加复杂的异步流程?

action - 异步提交 mutation,dispatch() 分发 - vuex(状态管理)

首先,你需要明白store.dispatch可以处理被触发的action的处理函数返回的Promise,并且store.dispatch仍旧返回Promise:

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

现在你可以:

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

在另外一个action中也可以:

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

最后,如果我们利用async / await,我们可以如下组合action:

// 假设 getData() 和 getOtherData() 返回的是 Promise

actions: {
  async actionA ({ commit }) { commit('gotData', await getData())
  },
  async actionB ({ dispatch, commit }) {
    await dispatch('actionA') // 等待 actionA 完成 commit('gotOtherData', await getOtherData())
  }
}
一个store.dispatch在不同模块中可以触发多个action函数。在这种情况下,只有当所有触发函数完成后,返回的Promise才会执行。

鹏仔微信 15129739599 鹏仔QQ344225443 鹏仔前端 pjxi.com 共享博客 sharedbk.com

免责声明:我们致力于保护作者版权,注重分享,当前被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理!邮箱:344225443@qq.com)

图片声明:本站部分配图来自网络。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

内容声明:本文中引用的各种信息及资料(包括但不限于文字、数据、图表及超链接等)均来源于该信息及资料的相关主体(包括但不限于公司、媒体、协会等机构)的官方网站或公开发表的信息。部分内容参考包括:(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供参考使用,不准确地方联系删除处理!本站为非盈利性质站点,本着为中国教育事业出一份力,发布内容不收取任何费用也不接任何广告!)