Vue3+TypeScript组件外存API数据到Pinia报错求助
解决组件外调用API并存储到Pinia的错误
问题根源
你在api.ts的模块顶部直接执行const store = useStore(),这段代码会在模块加载时立刻运行。但此时main.ts里的app.use(pinia)还没执行,Pinia还没被挂载到Vue应用上,自然找不到活跃的Pinia实例,就会抛出getActivePinia()的错误。
三种解决方案
方案1:在API方法内动态获取Store
不要在模块顶部初始化store,而是把useStore()的调用放到getData方法内部。此时组件的onMounted已经触发,Pinia实例早已激活:
修改api.ts:
import Axios from 'axios'; import useStore from './store'; const api = { getData() { // 这里调用useStore时,Pinia已经完成初始化 const store = useStore(); return Axios.get('/myapi').then((response) => { store.data = response.data; }); }, }; export default api;
方案2:把API请求逻辑移到Pinia的Action中
这是最贴合Pinia设计理念的做法,把数据获取和状态更新的逻辑统一放在Store里,代码更规整:
修改store.ts:
import { defineStore } from 'pinia'; import Axios from 'axios'; interface State { data: Data[] } const useStore = defineStore('app', { state: (): State => ({ data: [] }), getters: {}, actions: { async fetchData() { const response = await Axios.get('/myapi'); this.data = response.data; } }, }); export default useStore;
修改App.vue:
<template> <div> Hello world </div> </template> <script setup lang="ts"> import { onMounted } from "vue"; import useStore from "./store"; const store = useStore(); onMounted(() => { store.fetchData(); }) </script>
方案3:手动传入Pinia实例(适合复杂场景)
如果必须在模块初始化时就用到Store,可以在main.ts里把Pinia实例传给api模块:
修改api.ts:
import Axios from 'axios'; import useStore from './store'; import type { Pinia } from 'pinia'; let store: ReturnType<typeof useStore>; // 暴露初始化方法,接收Pinia实例 export const initApi = (pinia: Pinia) => { store = useStore(pinia); }; const api = { getData() { return Axios.get('/myapi').then((response) => { store.data = response.data; }); }, }; export default api;
修改main.ts:
import { createApp, App as Application } from 'vue'; import { createPinia } from 'pinia'; import App from './App.vue'; import api, { initApi } from './api'; const pinia = createPinia(); // 先初始化api模块的store initApi(pinia); const app = createApp(App); app.use(pinia); app.mount('#app');
总结
优先选方案2,逻辑集中在Store里更易维护;如果一定要单独抽离API文件,方案1是最简单直接的解决办法。
内容的提问来源于stack exchange,提问作者Cohchi
相关产品推荐
相关产品推荐

