我正在使用 Vue 3,包括 Composition API,另外还使用 Pinia 作为状态管理。
在选项 API 中,有一个方法 beforeRouteEnter,该方法内置于组件本身中。不幸的是,这个方法在组合 API 中不存在。这里,本来应该在 beforeRouteEnter 方法中的代码被直接写入 setup 方法中。但是,这意味着先加载并显示组件,然后执行代码,如果检查失败,则组件会重定向到错误页面等。
我的想法是直接在路由的 beforeEnter 方法中的路由配置中进行检查。但是,我无法访问 Pinia Store,尽管之前在 main.js 中调用了它,但它似乎尚未初始化。
控制台日志
Uncaught Error: [🍍]: getActivePinia was called with no active Pinia. Did you forget to install pinia?
const pinia = createPinia()
app.use(pinia)
This will fail in production.
路由器.js
import { useProcessStore } from "@/store/process";
const routes: Array<RouteRecordRaw> = [
{
path: "/processes/:id",
name: "ProcessView",
component: loadView("ProcessView", "processes/"),
beforeEnter: () => {
const processStore = useProcessStore();
console.log(processStore);
},
children: [
{
path: "steer",
name: "ProcessSteer",
component: loadView("ProcessSteer", "processes/")
},
{
path: "approve/:code",
name: "ProcessApprove",
component: loadView("ProcessApprove", "processes/")
}
]
},
];
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
});
export default router;
main.js
import { createApp } from "vue";
import "@/assets/bundle-bootstrap.css";
import App from "@/App.vue";
import { createPinia } from "pinia";
import router from "@/router";
import SvgIcon from "@/components/SvgIcon.vue";
const pinia = createPinia();
const app = createApp(App);
app.use(pinia);
app.use(router);
app.component("SvgIcon", SvgIcon);
router.isReady().then(() => {
app.mount("#app");
});
但是,我无法访问 Pinia Store,尽管它之前在 main.js 中调用过,但它似乎还没有初始化
在什么之前? Pinia 实例是使用
const pinia = createPinia();
after 导入 router
模块创建的 - 导入时,会执行所有副作用,包括对 createRouter()
的调用。创建路由器后,它将开始初始导航(在客户端 - 在服务器上,您需要使用 router.push()
触发它)- 如果您恰好位于与使用 Pinia 存储的守卫的路由匹配的 URL,则会发生 useProcessStore()
在 Pinia 创建之前...
您有两个选择:
useXXXStore()
调用发生在 之后 Pinia 创建 (createPinia()
) 并安装 (app.use(pinia)
)useXXXStore()
...// store.js
import { createPinia } from "pinia";
const pinia = createPinia();
export default pinia;
// router.js
import pinia from "@/store.js";
import { useProcessStore } from "@/store/process";
const routes: Array<RouteRecordRaw> = [
{
path: "/processes/:id",
name: "ProcessView",
component: loadView("ProcessView", "processes/"),
beforeEnter: () => {
const processStore = useProcessStore(pinia ); // <-- passing Pinia instance directly
console.log(processStore);
},
},
];
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
});
export default router;
// main.js
import { createApp } from "vue";
import App from "@/App.vue";
import store from "@/store.js";
import router from "@/router";
const app = createApp(App);
app.use(store);
app.use(router);
router.isReady().then(() => {
app.mount("#app");
});
希望这会有所帮助。 Vue 为我们需要存储的一些功能提供支持(在组件之外)。
为了解决这个问题,我只是在 Vue(beforeEach) 提供的函数中调用了
useStore()
函数,它就起作用了。
参考:https://pinia.vuejs.org/core-concepts/outside-component-usage.html
示例:
import { useAuthStore } from "@/stores/auth";
.
.
.
.
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes,
});
router.beforeEach(async (to, from) => {
const authStore = useAuthStore();
// use authStore Here
});
我在“beforeEach”方法中访问商店来管理授权时遇到同样的问题。
我在 main.js 中使用此方法,而不是在 router.js 中。 router.js 存储中无法访问。
在 piniCreate.js 中创建 pinia 实例
//piniaCreate.js
import { createPinia } from "pinia";
const pinia = createPinia();
export default pinia;
之后在 mainStore.js 中创建我的商店
import { defineStore } from 'pinia'
export const mainStore = defineStore('counter', {
state: () => {
return {
user: {
isAuthenticated: isAuthen,
}
}
},
actions: {
login(result) {
//...
this.user.isAuthenticated = true;
} ,
logOff() {
this.user.isAuthenticated = false;
}
}
});
然后我在main.js中使用了beforeEach方法
//main.js
import { createApp } from 'vue'
import App from './App.vue'
import pinia from "@/stores/piniaCreate";
import { mainStore } from '@/stores/mainStore';
import router from './router'
const app = createApp(App)
.use(pinia)
.use(router)
const store1 = mainStore();
router.beforeEach((from) => {
if (from.meta.requiresAuth && !store1.user.isAuthenticated) {
router.push({ name: 'login', query: { redirect: from.path } });
}
})
app.mount('#app');
可以在definestore的第二个参数中传入方法:
export const useAppStore = defineStore('app', () => {
const state = reactive({
appName: 'App',
appLogo: ''
})
return {
...toRefs(state)
}
})
router.beforeEach((to, from, next) => {
const apppStore = useAppStore()
next()
})
这解决了我的问题
import { createPinia, setActivePinia } from 'pinia';
setActivePinia(createPinia());
import {useUserStore} from "@/stores/user.js";
const userStore = useUserStore()
我已经通过添加延迟加载解决了这个问题
const routes = [
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]