前言
作者最近在学习pinia,作为vue官方推荐的状态管理库,pinia完美支持vue2和vue3。但是大部分的状态管理库都有一个痛点,无法原生支持数据持久化。
作者发现了一个pinia插件,可以完美解决这个痛点。只需三步,让你的pinia store实现数据持久化!
如果你已经了解pinia,可以跳转到这里
什么是pinia
pinia是一个全局状态管理工具,提供以下功能:
- 完整的ts支持
- 足够轻量,压缩有体积只有1kb左右
- 去除了被认为是冗余的mutations,只有state、getters,actions
- actions支持同步和异步
- 代码扁平化,没有模块嵌套,只有store的概念,store之间可以自由使用,且每一个store都是独立的
- 无需手动添加store,store一旦创建就会自动添加
- 支持Vue2和vue3
pinia安装
sh
npm install pinia -S
pinia引入
在main.ts中引入
ts
import { createApp } from 'vue'
//从pinia中导入createPinia这个hook函数
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
const app = createApp(App)
//调用createPinia函数,获取pinia实例
const pinia = createPinia()
//将pinia实例作为vue插件,在app里注册
app.use(pinia)
app.use(router)
app.mount('#app')
pinia使用
创建pinia store
基于vue约束,首先让我们在/src/目录下建立stores文件夹 /src/sotres
然后在sotres文件夹里创建pinia store
然后在该文件里编写我们的pinia store,我们这里使用组合式API的写法,如果你更熟悉state、getter和actions的声明式写法,可以去官网查看。
js
import { defineStore } from 'pinia'
export const useUserInfoStore = defineStore('user', () => {
const userName = "李卢"
const age = 20
return {
userName,
age
}
})
首先从pinia里导入definestore()函数,这个函数接收两个参数:
- StoreId:字符串,用于唯一标识store
- 回调函数:在这个回调函数里面编写代码,最后return一个对象,这个对象里的属性就是pinia仓库里的状态。这个状态可以被其他组件使用和修改。
请注意,只有回调函数返回的对象里的值,才能被其他组件访问
defineStore()函数会返回一个hook函数,我们用一个use开头的变量接收。使用use开头是vue写法约束,让别人一眼就知道,你这个是一个pinia store的hook函数。 最后我们将这个use开头的变量export,这样就可以在其他vue组件中导入使用
使用pinia store
我们首先从刚才编写的userInfo.ts文件中,导入pinia store的hook函数
js
import { useUserInfoStore } from "./stores/userInfo"
然后调用hook函数,获取该pinia store实例
js
const userInfoStore = useUserInfoStore()
现在我们就可以通过userInfoStore访问到定义的状态了
js
console.log(userInfoStore.userName)
console.log(userInfoStore.age)
//"李卢"
//20
最后附上完整代码:
vue
<template>
<div>
<div>{{ userInfoStore.userName }}</div>
<div>{{ userInfoStore.age }}</div>
</div>
</template>
<script setup lang="ts">
import { useUserInfoStore } from "./stores/userInfo";
const userInfoStore = useUserInfoStore();
</script>
最终呈现效果
我们也可以在其他组件中导入,实现组件之间的状态共享
通过插件实现pinia数据持久化
pinia和vuex都有一个通病,没有自带的持久化储存,页面刷新状态丢失。 可以通过pinia插件将数据持久化,pinia-plugin-persistedstate这个插件旧可以实现pinia数据持久化
什么是pinia-plugin-persistedstate
persistedstate
丰富的功能可以使 Pinia Store 的持久化更易配置:
- 与
vuex-persistedstate
相似的 API - 所有 Store 均可单独配置
- 自定义 storage 和数据序列化
- 恢复持久化数据前后的 hook
- 每个 Store 具有丰富的配置
- 兼容 Vue 2 和 3
- 无任何外部依赖
pinia-plugin-persistedstate安装
安装
sh
npm i pinia-plugin-persistedstate
注册pinia插件
在main.ts中添加
ts
import { createApp } from 'vue'
import { createPinia } from 'pinia'
//导入持久化插件
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
import App from './App.vue'
import router from './router'
const app = createApp(App)
const pinia = createPinia()
app.use(pinia)
app.use(router)
//pinia注册持久化插件
pinia.use(piniaPluginPersistedstate)
app.mount('#app')
请注意!如果你是通过npm create vue@latest创建的vue项目,且创建时添加了pinia 那么您的main.ts配置为:
js
import './assets/main.css'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
const app = createApp(App)
//这里注册的方式不一样,请注意
app.use(createPinia())
app.use(router)
app.mount('#app')
store启用数据持久化
创建Store时,向defineStore()传入第三个参数,即配置对象,将persist选项设置为true,同时将需要储存到localStorage里的数据用ref包裹
ts
import { defineStore } from 'pinia'
import { ref } from 'vue'
export const useUserInfoStore = defineStore('userInfo', () => {
const userName = ref("李卢")
const age = ref(20)
return {
userName,
age
}
},{
persist: true
})
这里作者踩坑了,如果不需要数据持久化的话,store里的数据无需ref()包裹,就可以获得响应性。 但是如果需要数据持久化的话,一定要将数据用ref()包裹。如果没包裹的话,持久化插件会失效。就是这一点困扰了作者很多天
插件实现数据持久化的方式
该插件的默认配置如下:
- 使用 localStorage 进行存储
store.$id
作为 storage 默认的 key- 使用 JSON.stringify 和JSON.parse进行序列化/反序列化
- 整个 state 默认将被持久化
最终效果
最后跟着作者一起来看看持久化效果吧
vue
<template>
<div>
<input type="text" v-model="userInfoStore.userName">
<input type="text" v-model="userInfoStore.age">
<div>{{ userInfoStore.userName }}</div>
<div>{{ userInfoStore.age }}</div>
</div>
</template>
<script setup lang="ts">
import { useUserInfoStore } from "./stores/userInfo";
const userInfoStore = useUserInfoStore();
</script>
初始化时,localStorage里没有存入数据 然后我们修改userName为李大卢,修改age 为21 可以看到,在localStorage中,pinia store的id作为了Key,对应的值是一个对象。 在这个对象里,变量名为键,变量的值为值
刷新界面后,我们的修改仍然还在。到这里我们就实现了数据通过插件非常简单的实现了数据持久化