在组件外使用一个 store

Pinia store 依靠 pinia 实例在所有调用中共享同一个商店实例。大多数时候,只需调用你的 useStore() 函数,非常开箱即用。例如,在 setup() 中,你不需要做任何其他事情。但在组件之外,情况就有点不同了。 在幕后,useStore() 给你的 app 注入了 pinia 实例。这意味着,如果 pinia 实例不能自动注入,你必须手动提供给 useStore() 函数。 你可以根据你所写的应用程序的种类,以不同的方式解决这个问题。

单页面应用

如果你不做任何 SSR(服务器端渲染),在用 app.use(pinia) 安装pinia 插件后,任何对 useStore() 的调用都会有效:

import { useUserStore } from '@/stores/user'
import { createApp } from 'vue'
import App from './App.vue'

// ❌  失败,因为它是在创建 pinia 之前被调用的
const userStore = useUserStore()

const pinia = createPinia()
const app = createApp(App)
app.use(pinia)

// ✅ 成功,因为 pinia 实例现在激活了
const userStore = useUserStore()

最简单的方法是将 useStore() 的调用放在 pinia 安装后一直运行的函数中,以确保其始终被应用。

让我们来看看这个在 Vue Router 的导航卫士中使用 store 的例子。

import { createRouter } from 'vue-router'
const router = createRouter({
  // ...
})

// ❌ 取决于引入的顺序,这将失败
const store = useStore()

router.beforeEach((to, from, next) => {
  // 我们想用这里的 store
  if (store.isLoggedIn) next()
  else next('/login')
})

router.beforeEach((to) => {
  // ✅ 这样做是可行的,因为路由器在安装完之后就会开始导航。
  // Pinia 也将被安装。
  const store = useStore()

  if (to.meta.requiresAuth && !store.isLoggedIn) return '/login'
})

服务端渲染应用

当处理服务端渲染时,你将必须把 pinia 实例传递给 useStore()。这可以防止 pinia 在不同的应用程序实例之间共享全局状态。

SSR 指南中有一整节专门讨论这个问题,这里只是一个简短的解释。