javascript - 如何仅在需要时将数据加载到 vuex 模块中?异步/等待的问题
问题描述
有没有办法一次性加载 vuex 存储的所有数据,但仅在需要时才加载?
我认为有,但我很挣扎,我不确定是不是因为我在 Javascript 承诺中误解了 Vuex 或 Async/Await。
这是一个示例商店Roles
。userRolesApi
发出 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 请求。
我试图尽可能详细地解释我正在尝试做什么,因为我实际上不确定我哪里出错了。我的问题是:
- 仅在需要时填充 vuex 存储的最佳方法是什么?
- 如果我的方法是一种好方法,那么我尝试异步/等待有什么问题?
解决方案
您的组件不应该关心他们请求资源的次数,我认为 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];
})({});
推荐阅读
- javascript - 当angularjs中的ng-disabled值为true时,如何在复选框中显示X标记
- java - 将文件上传到 Google Cloud Storage (Java)
- python - 错误:找不到 pytesseract 模块
- php - SoapClient - 超时 - 无法加载外部实体(但在本地主机上工作)
- javascript - 我的 javascript 函数无法运行所有代码
- java - 在交易引擎中进行排序的最佳解决方案是什么?
- hadoop - 如何增加 AM 可以在 Hadoop 中使用的最大 vCores?
- php - 如何解决(2/2)ErrorException View [dashboard] not found in laravel 5.4
- php - 如何在 woocommerce 中使用 user_id 或会话 id 获取购物车商品?
- ibm-mq - 为 XMS.NET 中的每个连接配置单独的 CCDT 文件