- A+
以下是一些 Pinia 的其他高阶功能:
storeToRefs()
:响应式解构仓库,保证解构出来的数据是响应式的数据。- 状态持久化:Pinia 并没有内置的状态持久化功能,但你可以使用第三方库或自定义插件来实现状态的持久化。例如,你可以使用
localStorage
或sessionStorage
来将状态保存在客户端。 - 插件系统:Pinia 允许你编写自定义插件,以扩展和定制状态管理功能。你可以创建插件来处理持久化、日志记录、错误处理等任务,以适应你的特定需求。
响应式解构storeToRefs()
背景
在组件中访问仓库state
,getters
,actions
时,总要在变量名前面带上仓库实例名,像下面这样,每个变量都这么写就会显得很代码很累赘。而直接解构的话,数据会丢失响应式。
import store from '@/store/senior.ts'; const userStore = store(); // 访问state中的money,需要敲上'userStore.' console.log(userStore.money); // 直接解构,会丢失响应式 const { age } = userStore;
使用
在组件中使用storeToRefs
可以保证解构出来的数据是响应式的数据。
import { storeToRefs } from 'pinia'; // ...... const { age } = storeToRefs(userStore); console.log(age.value); // 别忘了 .value 这个小尾巴~
状态持久化插件pinia-plugin-persist
pinia本身不提供持久化存储状态,这里我们使用插件pinia-plugin-persist
进行持久化存储。
1-安装
- yarn
yarn add pinia-plugin-persist
- npm
npm install pinia-plugin-persist
- pnpm
pnpm add pinia-plugin-persist
2-配置
在src/store/index.ts
中进行pinia的配置
import { createPinia } from 'pinia'; // 1-引入包 import piniaPersist from 'pinia-plugin-persist'; const pinia = createPinia(); // 2-使用pinia-plugin-persist插件 pinia.use(piniaPersist); export default pinia;
src/main.ts
// ...... import { createApp } from 'vue'; import App from './App.vue'; // 1-引入pinia配置文件 import pinia from '@/store/index.ts'; const app = createApp(App); // 2-使用pinia配置文件 app.use(pinia); app.mount('#app');
打开项目下的ts配置文件tsconfig.json
{ "compilerOptions": { "types": [ "pinia-plugin-persist" ] }, }
3-使用
组合式API写法
在仓库中的defineStore()
第三个参数进行配置。
src/store/senior.ts
export const store = defineStore( 'senior', () => { const age = ref(18); const money = ref(100); return { age, money } }, { persist: { enabled: true, // 启用持久化存储 // 存储策略,可以配置多个存储策略,一条策略对应一个存储 strategies: [ { key: 'local_age', // 存储的key名 storage: localStorage, // 存储方式 paths: ['money'] // 指定state字段进行存储 }, { key: 'session_age', storage: sessionStorage } ] } } );
persist
参数说明:
enabled
:(true
) 开启持久化存储。strategies
:(Array
) 配置存储策略,一条策略对应一个存储。key
:(String
) 存储的key名。storage
:(Storage
) 存储方式,默认值是sessionStorage
,可以是localStorage
,也可以自定义存储方式。paths
:(Array<string>
) 指定某些state字段进行存储。若不配置,默认对整个state进行存储。
选项式API写法
src/store/senior.ts
export const store = defineStore('senior', { state() { return { age: 18, money: 100, } }, persist: { enabled: true, strategies: [ { key: 'local_age', storage: localStorage, paths: ['money'] }, { key: 'session_age', storage: sessionStorage } ] } })
4-自定义存储方式(cookie
)
以下示例是对官方示例,进行优化的版本。
(1)安装js-cookie
- yarn
yarn add js-cookie
- npm
npm install js-cookie
- pnpm
pnpm add js-cookie
(2)定义仓库
src/store/senior.ts
import { defineStore } from "pinia"; import { ref } from 'vue'; import Cookies from 'js-cookie'; // 1-定义存储方式cookiesStorage const cookiesStorage: Storage = { setItem(key, state) { // 判断是值,还是整个仓库 const isKey = Object.keys(JSON.parse(state)).includes(key); if (isKey) { // 值 return Cookies.set(key, JSON.stringify(JSON.parse(state)[key]), { expires: 3 }); } else { // 仓库state return Cookies.set(key, state, { expires: 3 }); } }, getItem(key) { // 判断键值是否存在 let value = Cookies.get(key); // 这里应该需要判断是整个仓库state、还是值 // 但目前没有发现较好的判断方法,所以persist必须配置paths /* // 如果是整个仓库state return value; */ return value ? // 存在,返回对应的值(parse处理,保证和原类型一致) JSON.stringify({ [key]: JSON.parse(value) }) : // 不存在,不做parse处理,防undefined报错 JSON.stringify({ [key]: value }); } } export const store = defineStore('senior', () => { const age = ref(123456); return { age, } }, { persist: { enabled: true, strategies: [ { storage: cookiesStorage, // 2-使用cookiesStorage存储方式 key: 'age', paths: ['age'] // 3-必须配置paths指定state字段,否则数据会错乱 }, ] } });
!!!注意:目前,根据官方文档的示例以及笔者的实践,使用cookie进行持久化存储,
persist.strategies
必须要配置paths
属性,即无法默认存储整个state,否则数据会出现错乱(文章中就不演示了,有兴趣的小伙伴儿可自行尝试)。
插件系统
介绍
Pinia 插件是一个函数,函数接收一个参数context
(上下文对象),可以获取pinia
实例、app
应用等。
export functionmyPiniaPlugin(context) { context.pinia // 使用 `createPinia()` 创建的 pinia context.app // 使用 `createApp()` 创建的当前应用程序(仅限 Vue 3) context.store // 插件正在扩充的 store context.options // 定义存储的选项对象传递给`defineStore()` // ... };
然后使用 pinia.use()
将此函数传递给 pinia
:
pinia.use(myPiniaPlugin);
插件仅适用于在 将pinia传递给应用程序后创建的 store,否则将不会被应用。
功能
pinia官网描述pinia插件的功能:
- 向 Store 添加新属性
- 定义 Store 时添加新选项
- 为 Store 添加新方法
- 包装现有方法
- 更改甚至取消操作
- 实现本地存储等副作用
- 仅适用于特定 Store
- ……
向 Store 添加新属性
自定义插件函数返回(return
)一个对象,对象中就是需要增加的属性。
在src/store/index.ts
中,配置pinia插件。
import { createPinia } from 'pinia'; import { ref } from 'vue'; const pinia = createPinia(); // 1-定义插件:向store增加属性 const expandStore = () => { // 2-这里把需要增加的属性return出去即可 return { hello: ref(123) // 在所有store上添加'hello'状态 }; } // 3-使用插件 pinia.use(expandStore); export default pinia;
读取 Store 配置项
可以通过插件函数context.options
来获取每个store的额外配置,以便根据每个仓库的功能进行区别开发。
1-定义 Store 时添加新选项
- 在组合式API中,
defineStore()
的第三个参数就是仓库的配置项。 - 在选项式API中,直接在
defineStore()
的第二个参数(一个对象)中添加属性作为配置项。
src/store/senior.ts
组合式API
import { defineStore } from "pinia"; export const store = defineStore('senior', () => { return {} }, { haha: { option1: '123' } } );
选项式API
import { defineStore } from "pinia"; export const store = defineStore('senior', { state: () => ({}), getters: {}, actions: {}, haha: { option1: '123' } } );
2-插件中获取每个store的选项
src/store/index.ts
// 这里使用解构赋值,把options从context中解构出来 const expandStore = ({ options }) => { console.log('options', options); } pinia.use(expandStore);
监听仓库变化$subscribe()
和$onAction()
在插件中使用 store.$subscribe()
和 store.$onAction()
,可以监听仓库的变化。
pinia.use(({ store }) => { store.$subscribe(() => { // 在存储变化的时候执行 }) store.$onAction(() => { // 在 action 的时候执行 }) })
包装或重写现有方法
重写$reset方法
可以参考上一篇博文,重写了$reset方法:vue3探索——5分钟快速上手大菠萝pinia
import { createPinia } from 'pinia'; const pinia = createPinia(); // 1-使用pinia自定义插件 pinia.use(({ store }) => { // 2-获取最开始的State const initialState = JSON.parse(JSON.stringify(store.$state)); // 3-重写$reset()方法 store.$reset = () => { // 4-利用$patch()批量变更state,达到重置state的目的 store.$patch(initialState); } }); export default pinia;
暂时没有更多辣~