首页 > 解决方案 > 如何仅在需要时将数据加载到 vuex 模块中?异步/等待的问题

问题描述

有没有办法一次性加载 vuex 存储的所有数据,但仅在需要时才加载?

我认为有,但我很挣扎,我不确定是不是因为我在 Javascript 承诺中误解了 Vuex 或 Async/Await。

这是一个示例商店RolesuserRolesApi发出 axios 请求并返回一个承诺。

import {userRolesApi} from "../api";

export default {
    actions: {
        setRoles(context, roles) {
            context.commit('SET_ROLES', roles)
        },
        async loadRoles({state, dispatch}) {
            if (state.all === null) {
                return await userRolesApi.index().then(response => {
                    dispatch('setRoles', response.data)
                })
            }
        }
    },
    state: {
        all: null
    },
    getters: {
        findRoleFromId: (state) => (role) => {
            return _.find(state.all, {id: parseInt(role)})
        },
        findRoleFromName: (state) => (role) => {
            return _.find(state.all, {name: role})
        }
    },
    mutations: {
        SET_ROLES (state, roles) {
            state.all = roles
        },
    }
}

我想做的是findRoleFromId从 Vue 组件中调用。

然后将从 state 中的角色数组中获取角色state.all,但如果该数组尚不存在,也会从 API 构建该数组。

据我所知,从 getter 内部发出 api 请求是不好的做法,所以我改为loadRoles在操作中使用该方法。

但是我不能从 getter 调用动作,所以现在我将不得不loadRoles从其他地方调用,每次我认为我可能需要使用角色时。

所以我最终得到了一个这样的组件:

mounted() {
    this.$store.dispatch('loadRoles')
},
computed: {
    role() {
        // This will be null at first but update once the api request finishes.
        return this.$store.getters.findRoleFromId(this.roleId)
    }
},

这实际上非常有效!

但是,如果由于某种原因我this.$store.dispatch('loadRoles')快速连续调用两个组件,那么它将发出两次 api 请求。

我尝试使用 async/await 解决此问题,但这似乎无关紧要,在请求完成之前它不会停止处理。

作为测试将我的组件更改为此:

mounted() {
    this.$store.dispatch('loadRoles')
    this.$store.dispatch('loadRoles')
    this.$store.dispatch('loadRoles')
    this.$store.dispatch('loadRoles')
},
computed: {
    role() {
        return this.$store.getters.findRoleFromId(this.roleId)
    }
},

导致 api 请求立即被调用 4 次。而不是等待第一个完成,然后第二次尝试失败state.all === null检查并且不发出 api 请求。

我试图尽可能详细地解释我正在尝试做什么,因为我实际上不确定我哪里出错了。我的问题是:

  1. 仅在需要时填充 vuex 存储的最佳方法是什么?
  2. 如果我的方法是一种好方法,那么我尝试异步/等待有什么问题?

标签: javascriptajaxvue.jsasync-awaitvuex

解决方案


您的组件不应该关心他们请求资源的次数,我认为 userRolesApi 也不应该关心。如果最终您使用 fetch ,那么您可以缓存承诺,只要它没有被解决或拒绝,以后的请求将只返回该承诺。

const fetchOnce = ((cache) => (url, config) => {
    const cacheKey = `${JSON.stringify(config)} ${url}`;
    if (!cache[cacheKey]) {
        cache[cacheKey] = axios.get(url, config)
            .then((result) => {
                delete cache[cacheKey];
                return result;
            })
            .catch((error) => {
                delete cache[cacheKey];
                return Promise.reject(error);
            });
    }
    return cache[cacheKey];
})({});

推荐阅读