【问题标题】:How to load data into a vuex module only when it's needed? problems with async/await如何仅在需要时将数据加载到 vuex 模块中?异步/等待的问题
【发布时间】:2019-02-28 15:26:04
【问题描述】:

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

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

这是Roles 的示例商店。 userRolesApi 发出 axios 请求并返回一个 promise。

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
        },
    }
}

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

然后会从状态为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. 如果我的方法是一个好方法,那么我尝试异步/等待有什么问题?

【问题讨论】:

    标签: javascript ajax vue.js async-await vuex


    【解决方案1】:

    您的组件不应该关心他们请求资源的次数,我认为 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];
    })({});
    

    【讨论】:

    • 这个 fetchOnce 到底发生在哪里? cache 是在 vuex 存储状态还是其他地方?同样在您的回答中,如果第一个请求尚未完成,那么它仍然会出现缓存为空并再次调用的问题。
    • @JohnMellor if the first request hasn't finished ... call again => 不会的。您将在通常调用 fetch 的地方调用 fetchOnce,并将缓存传递给 IIFE,该 IIFE 返回一个与 fetch 具有相同签名的函数。
    • 有没有与 axios 等价的东西,而不必切换所有内容来获取?
    • @JohnMellor 使用axios.get更新了答案
    • 另外,(只是出于兴趣)您使用 return Promise.reject(error) 而不仅仅是 throw error 的任何原因?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-01
    • 1970-01-01
    • 2020-07-24
    • 2023-03-24
    • 2018-06-03
    • 1970-01-01
    相关资源
    最近更新 更多