Vue: не удается получить доступ к магазину Pinia до входа в vue-router
Я использую Vue 3, включая Composition API, а также Pinia в качестве управления состоянием.
В API опций есть метод beforeRouteEnter, встроенный в сам компонент. К сожалению, этот метод не существует в API композиции. Здесь код, который был бы в методе beforeRouteEnter, записывается непосредственно в метод setup. Однако это означает, что сначала загружается и отображается компонент, затем выполняется код и, если проверка не проходит, компонент перенаправляется, например, на страницу с ошибкой.
Моя идея заключалась в том, чтобы сделать мою проверку непосредственно в конфигурации маршрута в методе маршрута beforeEnter. Однако у меня нет доступа к магазину Pinia, который, похоже, еще не инициализирован, хотя он вызывается ранее в 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.
Router.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");
});
5 ответов
Однако у меня нет доступа к магазину Pinia, который, похоже, еще не инициализирован, хотя он вызывается ранее в main.js.
Перед чем? Экземпляр Pinia создается с помощью
const pinia = createPinia();
после _
router
модуль импортирован - пока он импортируется, все побочные эффекты, включая вызов
createRouter()
казнены. Как только маршрутизатор создан, он начинает свою начальную навигацию (на клиенте - на сервере вам нужно запустить его с помощью
router.push()
) - если вы оказались по URL-адресу, совпадающему с маршрутом с охранником, использующим магазин Pinia,
useProcessStore()
происходит до создания Пинии...
Использование хранилища вне компонента
У вас есть два варианта:
- либо вы убедитесь, что любой вызов происходит после создания Pinia (
createPinia()
) и установил(app.use(pinia)
) - или вы передаете экземпляр 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 обеспечивает поддержку некоторых функций, в которых нам нужно хранить (вне компонентов).
Чтобы решить эту проблему, я просто позвонил вuseStore()
внутри функции, предоставляемой Vue(beforeEach), и это сработало.
Ссылка: 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 недоступен.
создать экземпляр pinia в piniCreate.js
//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;
}
}
});
Затем я использовал метод beforeEach в файле main.js.
//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:
store.js
export const useAppStore = defineStore('app', () => {
const state = reactive({
appName: 'App',
appLogo: ''
})
return {
...toRefs(state)
}
})
router.js
router.beforeEach((to, from, next) => {
const apppStore = useAppStore()
next()
})
Я решил это, добавив ленивую загрузку
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')
}
]