【Nuxt3】使用Pinia

Pinia 是什么?

Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态。如果你熟悉组合式 API 的话,你可能会认为可以通过一行简单的 export const state = reactive({}) 来共享一个全局状态。对于单页应用来说确实可以,但如果应用在服务器端渲染,这可能会使你的应用暴露出一些安全漏洞。 而如果使用 Pinia,即使在小型单页应用中,你也可以获得如下功能:

  • Devtools 支持
    • 追踪 actions、mutations 的时间线
    • 在组件中展示它们所用到的 Store
    • 让调试更容易的 Time travel
  • 热更新
    • 不必重载页面即可修改 Store
    • 开发时可保持当前的 State
  • 插件:可通过插件扩展 Pinia 功能
  • 为 JS 开发者提供适当的 TypeScript 支持以及自动补全功能。
  • 支持服务端渲染

对比 Vuex 3.x/4.x

Vuex 3.x 只适配 Vue 2,而 Vuex 4.x 是适配 Vue 3 的。

Pinia API 与 Vuex(<=4) 也有很多不同,即:

  • mutation 已被弃用。它们经常被认为是极其冗余的。它们初衷是带来 devtools 的集成方案,但这已不再是一个问题了。
  • 无需要创建自定义的复杂包装器来支持 TypeScript,一切都可标注类型,API 的设计方式是尽可能地利用 TS 类型推理。
  • 无过多的魔法字符串注入,只需要导入函数并调用它们,然后享受自动补全的乐趣就好。
  • 无需要动态添加 Store,它们默认都是动态的,甚至你可能都不会注意到这点。注意,你仍然可以在任何时候手动使用一个 Store 来注册它,但因为它是自动的,所以你不需要担心它。
  • 不再有嵌套结构的模块。你仍然可以通过导入和使用另一个 Store 来隐含地嵌套 stores 空间。虽然 Pinia 从设计上提供的是一个扁平的结构,但仍然能够在 Store 之间进行交叉组合。你甚至可以让 Stores 有循环依赖关系。
  • 不再有可命名的模块。考虑到 Store 的扁平架构,Store 的命名取决于它们的定义方式,你甚至可以说所有 Store 都应该命名。

安装 Pinia

npm i pinia @pinia/nuxt --legacy-peer-deps

配置

nuxt.config.js文件中配置

// nuxt.config.js
export default defineNuxtConfig({
  // ... 其他配置
  modules: [
    // ...
    '@pinia/nuxt',
  ],
})

这样配置就完成了,正常使用 store 就好啦!

在 setup()外部使用 store

如果你想在 setup() 外部使用一个 store,记得把 pinia 对象传给 useStore()。我们会把它添加到上下文中,然后你就可以在 asyncData() 和 fetch() 中访问它了:

import { useStore } from '~/stores/myStore'

export default {
  asyncData({ $pinia }) {
    const store = useStore($pinia)
  },
}

自动引入

默认情况下,@pinia/nuxt 会暴露一个自动引入的方法:usePinia(),它类似于 getActivePinia(),但在 Nuxt 中效果更好。你可以添加自动引入来减轻你的开发工作:

// nuxt.config.js
export default defineNuxtConfig({
  // ... 其他配置
  modules: [
    // ...
    [
      '@pinia/nuxt',
      {
        autoImports: [
          // 自动引入 `usePinia()`
          'defineStore',
          // 自动引入 `usePinia()` 并重命名为 `usePiniaStore()`
          ['defineStore', 'definePiniaStore'],
        ],
      },
    ],
  ],
   imports: {
        dirs: ['./stores'],
    },
})

定义 Store

新建一个stores文件夹,然后在里面新建任意文件,比如说counter.ts,基础内容:

export const useCounter = defineStore('counter', {
  state: () => ({
    n: 2,
  }),

  getters: {
    // 相当于计算属性
    double: (state) => state.n * 2,
  },

  actions: {
    // 修改 state 中的值
    increment(amount = 1)
      this.n += amount
    },
  },
})

其他地方使用

比如说在App.vuesetup语法糖中

const counter = useCounter()

// 获取  state 的值
Let n = counter.$state.n

// 获取 getters 中的 double 计算属性
let double = counter.double

// 调用 actions 中的 increment 方法
counter.counter(1)

备注

能直接用 const counter = useCounter()是因为我们在nuxt.config.js里面配置了autoImportsimports,而useCounter 则是我们在counter.ts里面暴露时的变量名,
大概要补充的应该就只有这一点了

点赞

发表回复

电子邮件地址不会被公开。必填项已用 * 标注