前端技术之:如何在vuex状态管理action异步调用结束后执行UI中的方法

1、问题的起源

最近在作vue.js项目时,遇到了vuex状态管理action与vue.js方法互相通讯、互操做的问题。场景以下图所示:vue

2、第一种解决方法

例如,咱们在页面初始化的时候,须要从服务端经过API接口获取数据,数据获取成功前须要显示Loading状态框,数据获取完成后,须要将Loading状态框隐藏。ios

这是一种相对比较简单的应用场景,解决起来固然也比较简单。vuex

咱们能够经过state数据字段来实现,在state中存储一个loading字段,并设置默认值为false。axios

const store = new Vuex.Store({ state: { loading: false }, // ...... }); 

由于要对state.loading进行操做,因此,咱们须要定义一个mutation方法,用于更新loading状态数据。promise

const UPDATE_LOADING = 'updateLoading'; const store = new Vuex.Store({ // ......, mutations: { updateLoading (state, loading) { state.loading = loading; } }, // ...... }); 

而后,咱们声明一个action方法,用于从HTTP API获取数据。异步

const store = new Vuex.Store({ // ......, actions: { fetchData ({ commit }) { commit(UPDATE_LOADING, true); axios.get('...', { params: {...} }) .then(res => { // TODO 解析HTTP响应数据,进行相关的业务逻辑处理 }) .catch(err => { // TODO 进行相关的错误与异常处理 }) .finally(() => { commit(UPDATE_LOADING, false); }); } }, // ...... }) 

在页面模板中,咱们经过mapActions函数将vuex的action方法映射为vue.js中对象的方法。函数

import { mapActions } from 'vuex' export default { // ... methods: { ...mapActions([ 'fetchData', // ... ]) } } 

最后,在vue.js的mounted生命周期方法中调用经过mapActions映身的方法fetchData便可。fetch

export default { // ..., mounted() { this.fetchData(); }, // ... } 

3、第二种解决方法

上述的第一种解决方法,能够经过mutation修改state的状态数据控制UI上的数据渲染。但若是想要将获取到的结果数据传到UI组件是不行的,另外,若是想要在调用action方法执行完成后在UI中再去作一些事情也是行不通的。this

之前咱们知道,异步方法传递数据,能够经过回调函数的参数进行传递数据,因此,我提到的第二种解决办法就是经过回调函数实现的。spa

const store = new Vuex.Store({ // ......, actions: { fetchData ({ commit }, { params, callback }) { commit(UPDATE_LOADING, true); axios.get('...', { params }) .then(res => { callback(res); }) .catch(err => { // TODO 进行相关的错误与异常处理 }) .finally(() => { commit(UPDATE_LOADING, false); }); } }, // ...... }) 

4、第三种解决方法

以上两种方式虽然能够解决某些问题,但解决方法不够优雅,并且第一种方法具备很大的局限性。好比,不能回调主界面中的方法执行后续的操做,也不能自由地传递参数。第二种方法采用回调能够调用方法,也能够传参,但callback的调用是同步方式,代码风格也不是很好。因此,我比较提倡你们使用第三种方法,就是在action调用时返回一个Promise,这样在主界面就能够拿到这个promise对象,并进行链式执行后续的任务,也能够将action异步任务的结果数据传递给主UI。

const store = new Vuex.Store({ // ......, actions: { fetchData ({ commit }, { params }) { commit(UPDATE_LOADING, true); return axios.get('...', { params }) .then(res => { const { data } = res; return data; }) .finally(() => { commit(UPDATE_LOADING, false); }); } }, // ...... }) 

在主UI中,咱们就能够采用以下的方式进行后续的操做。

export default { // ..., mounted() { this.fetchData({ id: 1 }) .then(res => { // TODO 执行后续的任务 }) .catch(err => { // TODO 处理异常状况 }); }, // ... }
相关文章
相关标签/搜索