Vue3应用预加载多个Fetch请求并通过provide/inject共享数据咨询
问题解答
现有代码问题排查
首先你遇到的issues渲染成功率低的问题和provide执行时机无关,核心是现有代码存在两处明显错误:
- fetch调用后的
then({ data })写法错误,then方法需要传入回调函数,你直接传入了对象会抛出语法错误,你提到的items可以正常渲染大概率是粘贴代码时的手误 - issues数组的map逻辑中,你给每一项额外包了一层数组
return [{ ...c.attributes, id: c.id }],最终得到的是二维数组,如果你子组件按一维数组逻辑渲染,自然会出现展示异常
问题1:多并发fetch请求的最优实现
用Promise.all处理并发请求即可,ref本身是响应式引用,你provide的是ref的引用地址,只要后续ref.value更新,所有inject的子组件都能同步拿到最新值,不需要等待请求完成再执行provide:
import { ref, provide, onMounted } from 'vue' export default { setup() { const items = ref([]) const issues = ref([]) const fetchInitData = async () => { // 并发发起所有请求 const [listRes, issueRes] = await Promise.all([ fetch('/api/lists'), fetch('/api/issues') ]) // 批量处理返回结果 const [listData, issueData] = await Promise.all([ listRes.json(), issueRes.json() ]) // 赋值数据 items.value = listData?.data?.map(c => ({ ...c.attributes, id: c.id })) || [] issues.value = issueData?.data?.map(c => ({ ...c.attributes, id: c.id })) || [] } onMounted(() => { fetchInitData() }) // 直接传递ref引用即可,后续值更新子组件自动同步 provide('items', items) provide('issues', issues) return {} }, components: {} }
问题2:无Vuex的预加载数据持久化方案
以下是满足需求的轻量化实现方案:
App.vue作为应用根组件,整个生命周期内只会初始化一次,你在这里发起的请求本身就不会因为路由切换、视图切换重复触发。如果需要更灵活的复用逻辑,可以把请求封装为独立的组合式函数:
// composables/useInitData.js import { ref } from 'vue' // 模块顶层定义变量,全局单例只会初始化一次 const items = ref([]) const issues = ref([]) let isFetched = false export default function useInitData() { const fetchAll = async () => { // 已经请求过就直接返回,避免重复调用 if (isFetched) return const [listRes, issueRes] = await Promise.all([ fetch('/api/lists'), fetch('/api/issues') ]) const [listData, issueData] = await Promise.all([ listRes.json(), issueRes.json() ]) items.value = listData?.data?.map(c => ({ ...c.attributes, id: c.id })) || [] issues.value = issueData?.data?.map(c => ({ ...c.attributes, id: c.id })) || [] isFetched = true } return { items, issues, fetchAll } }
在App.vue中调用一次即可:
// App.vue import { provide, onMounted } from 'vue' import useInitData from './composables/useInitData' export default { setup() { const { items, issues, fetchAll } = useInitData() onMounted(() => { fetchAll() }) provide('items', items) provide('issues', issues) return {} } }
这个方案的优势:
- 所有数据存在组合式函数的顶层作用域,全局单例,整个应用生命周期内只会请求一次,切换视图不会重复发起请求
- 不需要引入Vuex/Pinia等状态管理库,逻辑轻量化
- 可以在任意组件直接引入
useInitData获取数据,不依赖inject也能使用
内容的提问来源于stack exchange,提问作者Nathan Azevedo
相关产品推荐
相关产品推荐

