Pinia中使用inject注入$zo实例返回undefined问题求助
Pinia Store中inject获取$zo实例返回undefined的原因及解决办法
我在使用vue-zo实现权限控制功能时,遇到一个问题:在Pinia的store中使用inject("$zo")返回undefined,但在App.vue中直接注入却能正常工作。
相关代码
GatesStore代码:
import { inject } from 'vue' import { defineStore } from "pinia"; export const useGatesStore = defineStore("api", () => { const $zo = inject("$zo"); const setRoles = () => { console.log($zo) } return { setRoles }; })
Main.js代码:
import './assets/base.scss' import 'bootstrap/dist/css/bootstrap.css' import 'nprogress/nprogress.css' import 'bootstrap-vue/dist/bootstrap-vue.css' import { BootstrapVue } from 'bootstrap-vue' import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; import { createPinia } from 'pinia' import { createApp, markRaw } from 'vue' import { router } from './router' import { VueClipboard } from '@soerenmartius/vue3-clipboard' import { VueZo } from 'vue-zo' import Modal from "vue-bs-modal"; import progressBar from './includes/progress-bar'; import App from './App.vue' import i18n from './includes/i18n' import 'notyf/notyf.min.css'; import { useAuthStore } from '@/stores'; const pinia = createPinia(); pinia.use(({ store }) => { store.router = markRaw(router) }); const app = createApp(App) app.config.errorHandler = () => null; app.config.warnHandler = () => null; app.use(pinia) const authStore = useAuthStore(); authStore.attempt(localStorage.getItem('token')).then(() => { app.use(router) .use(i18n) .use(BootstrapVue) .use(Modal) .use(VueClipboard) .use(VueZo) .component("font-awesome-icon", FontAwesomeIcon) .mount('#app') progressBar(router) })
问题原因
核心问题出在代码执行顺序上:
- 你先执行了
app.use(pinia),紧接着就实例化了useAuthStore()并调用异步方法attempt - 在异步回调执行之前,Pinia的所有store(包括
useGatesStore)已经完成初始化,而此时VueZo插件还未安装,$zo并没有被注入到应用的全局依赖容器中 - App.vue能正常获取
$zo,是因为组件渲染发生在app.mount('#app')之后——此时VueZo已经完成安装,依赖容器中已经存在$zo实例
解决方案
方案一:提前安装VueZo(优先推荐)
如果VueZo的安装不依赖auth验证结果,可以把app.use(VueZo)移到authStore调用之前,保证store初始化时$zo已存在:
const app = createApp(App) app.config.errorHandler = () => null; app.config.warnHandler = () => null; app.use(pinia) .use(VueZo) // 提前安装VueZo,保证依赖容器中存在$zo const authStore = useAuthStore(); authStore.attempt(localStorage.getItem('token')).then(() => { app.use(router) .use(i18n) .use(BootstrapVue) .use(Modal) .use(VueClipboard) .component("font-awesome-icon", FontAwesomeIcon) .mount('#app') progressBar(router) })
方案二:在方法内延迟获取$zo(适合必须在auth后安装VueZo的场景)
不在store的setup函数顶部直接inject,而是在需要使用的方法中获取,或通过当前实例访问全局属性:
import { inject, getCurrentInstance } from 'vue' import { defineStore } from "pinia"; export const useGatesStore = defineStore("api", () => { let $zo = inject("$zo"); const setRoles = () => { // 如果初始inject未获取到,从当前实例的全局属性中取 if (!$zo) { const instance = getCurrentInstance(); $zo = instance?.appContext.config.globalProperties.$zo; } console.log($zo) } return { setRoles }; })
方案三:通过Pinia插件注入$zo
在Pinia初始化时添加插件,将$zo直接注入到所有store实例中:
const pinia = createPinia(); pinia.use(({ store }) => { store.router = markRaw(router); // 确保这段代码在app.use(VueZo)之后执行 store.$zo = app.config.globalProperties.$zo; }); // 先安装VueZo,再挂载Pinia app.use(VueZo) .use(pinia)
内容的提问来源于stack exchange,提问作者Bryan van der Starre
相关产品推荐
相关产品推荐

