如何在Vue 3、Vuex结合Axios时避免重复API请求?
在Vue 3 + Vuex + Axios中避免重复API请求的实现方案
要实现首次访问路由时加载API数据、后续直接从缓存获取的需求,核心是在Vuex中维护数据缓存、加载状态和已加载标记,结合路由守卫触发请求,同时在action层做缓存判断与并发请求拦截。
1. 设计Vuex模块管理缓存与请求状态
先在Vuex中定义一个专门的模块,处理数据缓存、加载状态控制和请求逻辑:
// store/modules/dataModule.js import axios from 'axios' const state = { cachedData: null, // 存储缓存的数据 isLoading: false, // 标记是否正在请求数据 isLoaded: false // 标记是否完成首次加载 } const mutations = { SET_CACHED_DATA(state, data) { state.cachedData = data }, SET_LOADING(state, status) { state.isLoading = status }, SET_LOADED(state, status) { state.isLoaded = status } } const actions = { async fetchData({ state, commit }) { // 1. 已加载过数据,直接返回缓存 if (state.isLoaded) { return state.cachedData } // 2. 正在请求中,等待请求完成后返回结果(防止并发重复请求) if (state.isLoading) { return new Promise(resolve => { const checkInterval = setInterval(() => { if (!state.isLoading) { clearInterval(checkInterval) resolve(state.cachedData) } }, 50) }) } // 3. 发起新请求 commit('SET_LOADING', true) try { const response = await axios.get('/api/your-target-endpoint') commit('SET_CACHED_DATA', response.data) commit('SET_LOADED', true) return response.data } catch (error) { console.error('数据请求失败:', error) throw error // 抛出错误让调用方处理 } finally { commit('SET_LOADING', false) } }, // 可选:重置缓存,用于需要强制刷新数据的场景 resetDataCache({ commit }) { commit('SET_CACHED_DATA', null) commit('SET_LOADED', false) } } const getters = { getCachedData: state => state.cachedData, isDataLoading: state => state.isLoading, isDataLoaded: state => state.isLoaded } export default { namespaced: true, state, mutations, actions, getters }
记得将该模块注册到Vuex Store:
// store/index.js import { createStore } from 'vuex' import dataModule from './modules/dataModule' export default createStore({ modules: { dataModule } })
2. 在路由守卫中触发请求
在目标路由的beforeEnter守卫里调用Vuex的fetchData action,确保首次访问路由时自动请求数据,后续访问直接走缓存:
// router/index.js import { createRouter, createWebHistory } from 'vue-router' import store from '@/store' import TargetComponent from '@/components/TargetComponent.vue' const routes = [ { path: '/target-route', name: 'TargetRoute', component: TargetComponent, beforeEnter: async (to, from, next) => { // 触发数据请求,自动走缓存逻辑 await store.dispatch('dataModule/fetchData') next() } } ] const router = createRouter({ history: createWebHistory(process.env.BASE_URL), routes }) export default router
3. 组件中直接使用缓存数据
组件无需再发起请求,直接通过Vuex的getters获取缓存数据和状态:
<!-- components/TargetComponent.vue --> <template> <div class="data-container"> <div v-if="isLoading" class="loading">加载中...</div> <div v-else-if="cachedData" class="content"> <!-- 渲染数据 --> <pre>{{ cachedData }}</pre> </div> <div v-else class="empty">暂无数据</div> </div> </template> <script setup> import { computed } from 'vue' import { useStore } from 'vuex' const store = useStore() const cachedData = computed(() => store.getters['dataModule/getCachedData']) const isLoading = computed(() => store.getters['dataModule/isDataLoading']) </script>
额外优化说明
- 若需要强制刷新数据(如用户提交表单后),可先调用
resetDataCacheaction,再调用fetchData即可重新请求最新数据。 - 如需按请求参数做细粒度缓存,可将
cachedData改为对象,用请求参数作为key存储不同缓存结果。
内容的提问来源于stack exchange,提问作者Uzzal Hossain
相关产品推荐
相关产品推荐

