Pinia
Vuex 用于管理和多个组件共享状态(数据源)。现在,Vue 的官方状态管理库已更改为 Pinia,它由 Vue 核心团队维护。Pinia 具有与 Vuex 5 几乎完全相同或增强的 API,在 Vuex 5 RFC 中进行了描述。可以简单地将 Pinia 视为具有不同名称的 Vuex 5(Pinia 也适用于 Vue 2.x)。Vue 官方推荐使用 Pinia:
- 更强的团队协作约定。
- 与 Vue DevTools 集成,包括时间轴、组件内部审查和时间旅行调试。
- 模块热更新 (HMR)。
- 服务端渲染支持。
- 即使在 JavaScript 中也具有类型,为 JS 用户提供适当的 TypeScript 支持或自动完成功能。
- 与 TypeScript 一起使用时具有可靠的类型推断支持。
pinia-plugin-persistedstate
pinia-plugin-persistedstate 插件可以使 Pinia 存储的持久性变得更简单和可配置:
- 类似于 vuex-persistedstate 的 API。
- 单个 Store 的配置。
- 自定义存储方式和自定义序列化数据。
- 注水 hooks。
- 与 Vue 2 和 3 兼容。
- 没有外部依赖。
- 体积超小(<1kB gzipped)。
示例
- 使用 npm create vite@latest命令创建 vite 项目:
- Select a framework选择 Vue;
- Select a variant选择- Customize with create-vue;
- Add Pinia for state management?选择 Yes。
- 安装后,在 src 下面会生成一个 stores 文件夹和一个 counter.js 示例文件。可以看到默认使用了 Composition API 写法,导出了一个响应属性 count、一个计算属性 doubleCount 和一个方法 increment。内容如下: - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12- import { ref, computed } from 'vue' 
 import { defineStore } from 'pinia'
 export const useCounterStore = defineStore('counter', () => {
 const count = ref(0)
 const doubleCount = computed(() => count.value * 2)
 function increment() {
 count.value++
 }
 return { count, doubleCount, increment }
 })
- 将 App.vue 文件修改为以下即可引用 counter.js 中定义的 Store: - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13- <template> 
 {{ countStore.count }}
 <hr>
 {{ countStore.doubleCount }}
 <hr>
 <button @click="countStore.increment">increment</button>
 </template>
 <script setup>
 import { useCounterStore } from "./stores/counter"
 const countStore = useCounterStore()
 </script>
 <style>
 </style>- 当点击按钮时,响应属性 count 和计算属性 doubleCount 都会改变。但是,刷新页面后,它们都会恢复为 0,说明数据没有被持久化。 
- 安装持久化插件: - 1 - npm i pinia-plugin-persistedstate 
- 修改 src/main.js 文件: - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12- import { createApp } from 'vue' 
 import { createPinia } from 'pinia'
 import App from './App.vue'
 import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
 import './assets/main.css'
 const app = createApp(App)
 app.use(createPinia().use(piniaPluginPersistedstate))
 app.mount('#app')
- 修改 counter.js 文件: - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14- import { ref, computed } from 'vue' 
 import { defineStore } from 'pinia'
 export const useCounterStore = defineStore('counter', () => {
 const count = ref(0)
 const doubleCount = computed(() => count.value * 2)
 function increment() {
 count.value++
 }
 return { count, doubleCount, increment }
 }, {
 persist: true,
 })- 当点击 increment 按钮时,响应属性 count 和计算属性 doubleCount 都会改变。刷新页面后可以看到,它们也都显示为刷新之前的数据,说明数据已经被持久化了。 
- 插件预先配置了以下内容: 
- localStorage 作为存储。
- store.$id 作为存储的默认键,即 defineStore 的第一个参数。
- JSON.stringify/JSON.parse 作为序列化器/反序列化器。
- 所有属性都会被持久化到本地存储中。
但是,可以将传递一个对象给 store 的 persist 属性来配置持久性。
| 1 | import { stringify, parse } from 'zipson' | 
- key 用于引用存储中存储的反序列化数据的密钥。
- storage 将数据持久保存到的存储类型。必须有 getItem: (key: string) => string | null 和 setItem: (key: string, value: string) => void 方法。
- paths 持久化属性数组。 [] 表示没有状态被持久化, undefined 或 null 表示整个状态被持久化。
- serializer 自定义序列化程序在持久化数据之前序列化数据,并在重新水化存储之前反序列化数据。必须同时有 serialize: (value: StateTree) => string 和 deserialize: (value: string) => StateTree 方法。
- beforeRestore 钩子函数在恢复持久状态之前运行。该钩子可以访问整个 PiniaPluginContext。这可用于在水合之前强制执行特定操作。
- afterRestore 钩子函数在恢复持久状态后运行。该钩子可以访问整个 PiniaPluginContext。这可用于在水合后强制执行特定操作。
- debug 设置为 true 时,在持久化/水合存储时可能发生的任何错误都将记录为 console.error。
- 全局持久性配置:初始化插件时不使用 pinia-plugin-persistedstate 的默认导出项,而使用公开的 createPersistedState 方法使用全局选项初始化插件。这些选项成为应用内所有 Store 的新默认选项。修改 src/main.js 文件:这样,默认情况下,每个声明的 Store 中的 persist: true 配置都会将数据持久化到sessionStorage 中。但是传递给单个 Store 的 persist 配置的任何选项都可以覆盖其在全局选项中声明的对应项。可用的全局选项包括:1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19import { createApp } from 'vue' 
 import { createPinia } from 'pinia'
 import App from './App.vue'
 // import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
 import { createPersistedState } from 'pinia-plugin-persistedstate'
 import './assets/main.css'
 const app = createApp(App)
 // const pinia = createPinia().use(piniaPluginPersistedstate)
 const pinia = createPinia().use(createPersistedState({
 storage: sessionStorage,
 paths: ['count', 'count2'],
 }))
 app.use(pinia)
 app.mount('#app')
- storage
- serializer
- beforeRestore
- afterRestore
- 单个 Store 可以有多个持久性属性配置:可以将数据保存到不同的存储中,persist 选项可以接受一系列配置。这样,count 值将被持久化到 localStorage,而 count2 值将被持久化到 sessionStorage。1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27// src/stores/counter.js 
 import { ref, computed } from 'vue'
 import { defineStore } from 'pinia'
 export const useCounterStore = defineStore('counter', () => {
 const count = ref(0)
 const count2 = ref(0)
 const doubleCount = computed(() => count.value * 2)
 function increment() {
 count.value++
 count2.value++
 }
 return { count, count2, doubleCount, increment }
 }, {
 // persist: true,
 persist: [
 {
 paths: ['count'],
 storage: localStorage,
 },
 {
 paths: ['count2'],
 storage: sessionStorage,
 },
 ],
 })
GitHub 源码
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 张坤的博客!
 评论