在 route 中使用 Pinia store 時,不同的 route guard 常常會需要用到同一個 store,我一開始想要少寫一點程式碼XD,減少重複呼叫建立 store 實例,於是將 useStore 引入 route.js,在最外層的 scope 呼叫建立 store 實例,但這個方法會報錯。
會報錯的範例:
import { useHotelStore } from "@/stores/hotel.js";
const hotelStore = useHotelStore();
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    //略
    {
      path: "/rooms",
      name: "rooms",
      component: () => import("../views/RoomsView.vue"),
      async beforeEnter(to, from) {
        await hotelStore.getRooms();
      },
    },
    {
      path: "/room/:id",
      name: "room",
      component: () => import("../views/RoomView.vue"),
      async beforeEnter(to) {
        const roomID = to.params.id;
        await hotelStore.getRoom(roomID);
      },
    },
  ],
});
接下來會說明報錯的原因和正確的寫法。

為什麼會報錯? 這個和 pinia 實例初始化的時機有關。
所有 stores 都依賴 pinia 這個實例,來共享所有的 store 實例。
在 main.js 透過 createPinia() 建立 pinia 實例後,每次在元件中使用 store,其實都是把 pinia 實例從 app 層 inject 到元件中,所以一般在元件內呼叫使用 store 都可以正常運作,因為元件的 setup() 都會在 app.use(createPinia()) 後才執行。
來看看 main.js,為什麼在 route.js 內不能直接呼叫 pinia 的 store:
import { createApp } from "vue";
import { createPinia } from "pinia";
import App from "./App.vue";
import router from "./router";
import "./assets/main.css";
const app = createApp(App);
app.use(createPinia());
app.use(router);
app.mount("#app");
在引入 router 檔案的時候(import router from "./router";),就會先執行 route.js,讀取到 useHotelStore 就會報錯,因為這時候 pinia 還沒有實體化,沒有辦法取到 useHotelStore。
那什麼時候會踩到坑?
想要在 Vue 元件以外的地方使用 Pinia store 的時候,最常見的情境應該就是在 navigation guard 內使用 store 的時候。
正確作法其實沒有什麼特殊的技巧,就是在每次定義 navigation guard 的 callback 時,都要乖乖呼叫 useStore 建立 store 實例。
正確示範如下:
import { useHotelStore } from "@/stores/hotel.js";
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    //略
    {
      path: "/rooms",
      name: "rooms",
      component: () => import("../views/RoomsView.vue"),
      async beforeEnter(to, from) {
        const hotelStore = useHotelStore();
        await hotelStore.getRooms();
      },
    },
    {
      path: "/room/:id",
      name: "room",
      component: () => import("../views/RoomView.vue"),
      async beforeEnter(to) {
        const roomID = to.params.id;
        const hotelStore = useHotelStore();
        await hotelStore.getRoom(roomID);
      },
    },
  ],
});
一開始踩到雷的時候蠻困擾的,還是看 stackoverflow 去解 bug,結果,後來發現官方文件根本就有寫哈哈哈(請見參考資料),只是一開始學習 Pinia 時,還不太懂這個主旨的含意跟情境,所以就先跳過這個篇章了 ╥﹏╥
果然...還是要乖乖看官方文件啊~~