【问题标题】:Vue: Can't access Pinia Store in beforeEnter vue-routerVue:在进入 vue-router 之前无法访问 Pinia Store
【发布时间】:2022-01-14 13:00:50
【问题描述】:

我正在使用 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.

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");
});

【问题讨论】:

  • 我也找到了这个,但这不适合我的情况……在这里,在 createRouter() 之后,在 router.beforeEach() 中调用了 pinia 商店……但是我仅在某些路由中需要它,并希望在路由数组中单个路由的 beforeEnter 中调用它,然后在 createRouter() 函数中作为参数传递

标签: vue.js vue-router vuejs3 pinia


【解决方案1】:

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

在什么之前? Pinia 实例是用const pinia = createPinia(); 创建的 router 模块被导入之后——当它被导入时,包括对createRouter() 的调用在内的所有副作用都会被执行。创建路由器后,它开始进行初始导航(在客户端 - 在服务器上,您需要使用 router.push() 触发它) - 如果您恰好位于与使用 Pinia 商店的保护的路由匹配的 URL,则 useProcessStore() 会发生在创建 Pinia 之前...

Using a store outside of a component

你有两个选择:

  • 要么确保任何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");
});

【讨论】:

  • 我已经根据您的示例修改了我的代码:我创建了一个 store.js,其中创建了 Pinia 实例,根据代码示例将其包含在 main.js 和 router.js 中并将“Pinia”传递给 useProcessStore 函数。尽管如此,我仍然收到相同的错误消息。
  • @Josh 很好用——我现在在我自己的应用程序中使用它。事实上,即使没有将 Pinia 实例传递给路由保护中的useStore(),它也可以工作(初始导航总是在应用程序创建后触发 - 这是有道理的,因为现在(与路由器 v3 相对)all navigations are asynchronous。检查你是否没有在您导入到main.js 的任何文件中调用useStore()。还要检查您是否拥有Pania 和Router 的最新版本
  • 我刚刚更新了所有的包和依赖项,虽然大多数已经是最新的了。我在 main.js 中有一个组件可以在调用 Pinia 商店的整个应用程序中使用。但是,这没有什么区别,因为当我从 main.js 中注释掉组件时也会出现错误消息。
  • 我刚刚发现了问题。在导航守卫中,我调用了 useXXXStore(pinia),但在这家商店内,我又调用了一些商店……我必须将 pinia 传递给那些商店才能正常工作。非常感谢你:)
【解决方案2】:

可以在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()
})

【讨论】:

    猜你喜欢
    • 2019-07-01
    • 1970-01-01
    • 2017-04-26
    • 2020-10-23
    • 1970-01-01
    • 2017-05-21
    • 2022-12-10
    • 2022-08-06
    • 2021-09-28
    相关资源
    最近更新 更多