Vue3中pinia使用及状态持久化存储
一、pinia基本使用
1.安装pinia
npm install pinia
2.main.js注册
import { createPinia } from 'pinia'
app.use(createPinia())
3.定义store
创建src/store/index.js
import { defineStore } from 'pinia' export const useCommentStore = defineStore('comment', { // 静态数据 state: () => { return { curCommentlist: [] } }, // 相当于计算属性(有数据缓存) getters: { getCurCommentlist(state) { return state.curCommentlist } }, // actions即可以是同步函数也可以是异步函数 actions: { changeCommentlist(curCommentlist) { this.curCommentlist = curCommentlist }, } })
4.页面使用
// 引入pinia仓库 import store from '../stores/index' import { storeToRefs } from 'pinia' const { useLoginStore, useCommentStore } = store const commentStore = useCommentStore() const curUsername = useLoginStore().getCurUsername // 无需赋值操作,getters计算属性获取即可 const { curCommentlist } = storeToRefs(commentStore) // 对状态进行赋值操作并保持响应式,不能使用getters
二、state修改方式
大致有如下四种修改state状态值的方式
// 引入pinia仓库 import { useLoginStore } from '../stores/loginStore.js' import { storeToRefs } from 'pinia' const loginStore = useLoginStore() const { curUsername } = storeToRefs(loginStore) const router = useRouter() const formState = reactive({ username: '', password: '', remember: true, }); const onFinish = (values) => { const { username } = values // localStorage.setItem('username', username) // 改为如下pinia存储状态 // pinia start // 方式一:最简单的方法,如下 // 解构后更改方式 curUsername.value = username; // 解构前更改方式 // loginStore.curUsername = username; // 方式二:若要同时修改多个数据,建议使用$patch来实现批量更新,在内部做了优化 // loginStore.$patch({ // curUsername: username // }) // 方式三:更好的批量更新方法,通过$patch传递一个函数来实现,这里的state就是useLoginStore容器中的state // loginStore.$patch((state) => { // state.curUsername = username // }); // 方式四:通过 actions 来修改数据 // loginStore.changeCurUsername(username); // pinia end router.push('/commentOn') };
三、getters使用及注意事项
1.Getter 完全等同于 Store 状态的计算属性;Getters 函数的第一个参数是 state 对象
2.将参数传递给 getter (回调函数)
Getter 只是幕后的计算属性,因此无法向它们传递任何参数。但是,您可以从 getter 返回一个函数来接受任何参数,请注意,执行此操作时,getter 不再缓存,它们只是您调用的函数。但是,您可以在 getter 本身内部缓存一些结果,这并不常见,但性能更高
import { defineStore } from 'pinia' // 导入 pinia 中的功能模块 // 创建容器 // 参数一:容器名 // 参数二:容器的内容 const useMainStore = defineStore('main', { // pinia 状态管理的数据,通过箭头函数返回一个对象 // 相当于 vue 中的 data 数据 state: () => { return { count: 1, } }, // 相当于 vue 中的 computed 计算属性 getters: { // 定义的 getters,第一个参数就是该容器的 state comp(state) { return (num: number) => { return state.count + num } } }, }) // 导出容器 export { useMainStore }
// 组件中使用
<template>
<!-- 后面相同的调用,都是基于第一次计算的值 -->
<p>{{ mainStore.comp(2) }}</p>
<p>{{ mainStore.comp(3) }}</p>
<p>{{ mainStore.comp(4) }}</p>
</template>
<script setup lang="ts">
// 导入 pinia 实例
import { useMainStore } from '../store/index'
// 实例化容器
const mainStore = useMainStore()
</script>
<style scoped></style>
3.getter中的this
getter中同样可以使用 this,但是 TS 无法推导类型,需要手动指定返回值类型:
// 类似于组件的computed,用来封装计算属性,有缓存的功能 getters: { // 传入 state [可选参数] // computeds(state){ // console.log('getter运行了') // return state.count + 1 // } // !getter 中同样可以使用 this ,但是 TS 无法推导类型,需要手动指定返回值类型 computeds():number { console.log('getter运行了') return this.count + 1 } },
4.访问其它getter
与计算属性一样,您可以组合多个 getter。通过此访问任何其他 getter:
getters: { computeds():number{ console.log('getter运行了') return this.count+2 }, double():number{ this.foo = this.computeds * 2 return this.foo } },
5.访问其它容器的actions 或getter
直接导入并实例化容器后,使用即可,与前面的跨容器调用一致,不再展示示例代码
注意事项:
- 无更改state状态值操作,getters获取即可;需要更改state状态值,不能使用getters
- 组件视图需要更新,应该使用响应式api storeToRefs;视图无需依赖state更新直接用getters获取state即可
// pinia 获取列表 import { storeToRefs } from 'pinia' import store from '../stores/index.js' const { useLoginStore, useCommentStore } = store const curUsername = useLoginStore().getCurUsername // 视图无需依赖更新使用getters获取即可 const commentStore = useCommentStore() const { curCommentlist } = storeToRefs(commentStore) // 页面视图更新需要使用响应式
四、pinia持久化存储
1.手动利用localStorage或sessionStorage进行存储
// 不使用pinia-plugin-persist进行持久化操作 // 通过 store 的 $subscribe() 方法查看状态及其变化;subscriptions 只会在 patches 之后触发一次 // useLoginStore().$subscribe((mutation, state) => { // // import { MutationType } from 'pinia' // mutation.type // 'direct' | 'patch object' | 'patch function' // // 与 loginStore.$id 相同 // mutation.storeId // 'login' // // 仅适用于 mutation.type === 'patch object' // mutation.payload // 补丁对象传递给 to loginStore.$patch() // console.log('mutation', mutation); // // 每当它发生变化时,将整个状态持久化到本地存储 // localStorage.setItem('login', JSON.stringify(state)) // }) // 1. 保存数据 const instance = useLoginStore(); instance.$subscribe((_, state) => { localStorage.setItem('login-store', JSON.stringify({ ...state })); }); // 2. 获取保存的数据,先判断有无,无则用先前的 const old = localStorage.getItem('login-store'); if (old) { instance.$state = JSON.parse(old); }
2.利用持久化工具 pinia-plugin-persist
- 安装
npm i pinia-plugin-persist --save
- main.js引入
// 引入pinia仓库 import { createPinia } from 'pinia' // 持久化存储pinia import piniaPluginPersist from 'pinia-plugin-persist' const store = createPinia() store.use(piniaPluginPersist) const app = createApp(App) app.use(store)
- store中的配置参数 persist
import { defineStore } from 'pinia' export const useLoginStore = defineStore('login', { // 静态数据 state: () => { return { token: '', curUsername: '', } }, persist: { enabled: true, // 自定义持久化参数 strategies: [ { // 自定义key key: 'login_store', // 自定义存储方式,默认sessionStorage storage: localStorage, // 指定要持久化的数据,默认所有 state 都会进行缓存,可以通过 paths 指定要持久化的字段,其他的则不会进行持久化。 paths: ['curUsername'], } ] }, // 相当于计算属性(有数据缓存) getters: { getCurUsername(state) { return state.curUsername }, }, // actions即可以是同步函数也可以是异步函数 actions: { changeCurUsername(curUsername) { this.curUsername = curUsername }, } })