Vue:无法在输入vue-router之前访问Pinia Store

问题描述 投票:0回答:6

我正在使用 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");
});

vue.js vue-router vuejs3 pinia
6个回答
23
投票

但是,我无法访问 Pinia Store,尽管它之前在 main.js 中调用过,但它似乎还没有初始化

在什么之前? Pinia 实例是使用

const pinia = createPinia();
after 导入
router
模块创建的 - 导入时,会执行所有副作用,包括对
createRouter()
的调用。创建路由器后,它将开始初始导航(在客户端 - 在服务器上,您需要使用
router.push()
触发它)- 如果您恰好位于与使用 Pinia 存储的守卫的路由匹配的 URL,则会发生
useProcessStore()
在 Pinia 创建之前...

在组件外部使用存储

您有两个选择:

  • 确保任何
    useXXXStore()
    调用发生在 之后 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");
});

9
投票

希望这会有所帮助。 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
});

1
投票

我在“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');

0
投票

可以在definestore的第二个参数中传入方法:

store.js

export const useAppStore = defineStore('app', () => {
  const state = reactive({
    appName: 'App',
    appLogo: ''
  })

  return {
    ...toRefs(state)
  }
})

路由器.js

router.beforeEach((to, from, next) => {
  const apppStore = useAppStore()
  next()
})

0
投票

这解决了我的问题

import { createPinia, setActivePinia } from 'pinia';
setActivePinia(createPinia());

import {useUserStore} from "@/stores/user.js";
const userStore = useUserStore()

-2
投票

我已经通过添加延迟加载解决了这个问题

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')
  }
]
© www.soinside.com 2019 - 2024. All rights reserved.