Vue.js多组件复用server_list:如何优化单次获取避免重复请求?
嘿,这个场景太常见了!重复发起相同请求不仅浪费服务器资源,还可能导致不同组件拿到的数据不一致,给你几个实用的优化方案,你可以根据项目规模和架构选最适合的:
方案1:用Pinia/Vuex做状态管理(推荐中大型项目)
这是Vue生态里最规范的状态共享方案,把server_list存到全局状态中,所有组件直接复用已有数据,请求逻辑只在状态管理层处理一次。
以Vue3常用的Pinia为例:
// stores/serverStore.js import { defineStore } from 'pinia' import { fetch_server_list } from '@/api' export const useServerStore = defineStore('server', { state: () => ({ serverList: [], isLoading: false }), actions: { async getServerList() { // 如果已有数据,直接返回,避免重复请求 if (this.serverList.length > 0) return this.isLoading = true try { this.serverList = await fetch_server_list() } catch (err) { console.error('获取服务器列表失败:', err) } finally { this.isLoading = false } } } })
然后在需要用数据的组件里直接调用:
<!-- component_foo.vue --> <script setup> import { useServerStore } from '@/stores/serverStore' import { onMounted } from 'vue' const serverStore = useServerStore() onMounted(() => { // 不管多少组件调用,只有第一次会发起实际请求 serverStore.getServerList() }) </script> <template> <div v-if="serverStore.isLoading">加载中...</div> <ul v-else> <li v-for="server in serverStore.serverList" :key="server.id">{{ server.name }}</li> </ul> </template>
方案2:用Provide/Inject(适合层级较深的组件)
如果你的组件层级比较深,不想用全局状态管理,可以在根组件或者公共父组件里一次性请求数据,再通过provide把数据传递下去,子组件用inject接收。
<!-- App.vue(根组件) --> <script setup> import { ref, provide, onMounted } from 'vue' import { fetch_server_list } from '@/api' const serverList = ref([]) const isLoading = ref(false) async function loadServerList() { if (serverList.value.length) return isLoading.value = true try { serverList.value = await fetch_server_list() } catch (err) { console.error('请求失败:', err) } finally { isLoading.value = false } } onMounted(() => { loadServerList() }) // 把数据提供给所有子组件 provide('serverList', serverList) provide('isLoading', isLoading) </script>
子组件里直接接收:
<!-- component_bar.vue --> <script setup> import { inject } from 'vue' const serverList = inject('serverList') const isLoading = inject('isLoading') </script> <template> <div v-if="isLoading">加载中...</div> <div v-else>当前服务器数量:{{ serverList.length }}</div> </template>
方案3:封装单例API模块(适合小型项目)
如果项目比较小,不想引入状态管理库,可以封装一个带缓存的API模块,让所有组件调用这个模块的方法,自动复用缓存数据。
// api/server.js // 缓存数据和请求状态 let serverListCache = null let isFetching = false export async function getServerList() { // 有缓存直接返回 if (serverListCache) return serverListCache // 防止并发请求(多个组件同时调用时,只发起一次请求) if (isFetching) { await new Promise(resolve => setTimeout(resolve, 100)) return getServerList() } isFetching = true try { const data = await fetch_server_list() serverListCache = data return data } catch (err) { console.error('获取服务器列表失败:', err) throw err // 抛出错误让组件自行处理 } finally { isFetching = false } }
组件里调用这个方法就行:
<!-- component_foo.vue --> <script setup> import { ref, onMounted } from 'vue' import { getServerList } from '@/api/server' const serverList = ref([]) onMounted(async () => { try { serverList.value = await getServerList() } catch (err) { // 这里处理请求失败的情况 } }) </script>
总结一下
- 中大型项目优先选Pinia/Vuex,状态管理更规范,还能方便处理数据更新、缓存失效等场景;
- 组件层级深且不想用全局状态,选Provide/Inject;
- 小型项目或者只需要简单缓存,用单例API模块就足够了。
内容的提问来源于stack exchange,提问作者sof-03
相关产品推荐
相关产品推荐

