Pinia 插件开发

598 阅读1分钟

前面章节介绍了Pinia的使用,本章节用两个场景介绍下Pinia的插件开发

  1. reset方法
  2. 自动储存storage功能,

注册插件

先回顾下pinia是如何在vue中注册的

import { createApp } from 'vue'
import { createPinia } from 'pinia'

const app = createApp(App)
app.use(createPinia())
app.mount('#app')

pinia的插件实际上就是一个函数,只需要调用createPinia().use()方法即可注册插件

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import {piniaPlugins} from "@/plugins/piniaPlugins";

const app = createApp(App)

// 创建pinia
const pinia = createPinia()
// 注册pinia插件
pinia.use(piniaPlugins)

// 将pinia在vue中注册
app.use(pinia)
app.mount('#app')

pinia插件是一个函数,函数接受一个PiniaPluginContext类型的参数

import {PiniaPluginContext} from "pinia";

export function piniaPlugins({pinia, app, store, options}: PiniaPluginContext){
    // pinia: pinia实例
    // app: vue实例
    // store: 当前调用defineStore的状态
    // options: 当前调用defineStore的配置
}

封装reset方法

pinia的使用风格与vue一样,分为Options API和Composition API。但在使用Composition API时发现,$reset方法不能正常使用,于是打算自己封装一个

export function piniaPlugins({store}: PiniaPluginContext){
        // 深拷贝初始状态
        const state = deepClone(store.$state)
        // 向当前状态store里添加reset方法
        store.reset = function (){
                // reset方法将状态替换为初始状态
                store.$state = state
        }
}

使用

export const useCountStore = defineStore('countTest', ()=>{
    const count = ref(0)
    return {
        count
    }
})
const countStore = useCountStore()
function onReset(){
  countStore.reset()
}

自动储存storage功能

我们使用全局状态时经常需要数据持久化,通常做法就是在actions方法里将新的值保存在storage里

export const useTokenStore = defineStore('tokenTest', {
    state: ()=>({
        token: localStorage.getItem('token')
    }),
    actions: {
        changeToken(tokenNew: string){
            this.token = tokenNew
            localStorage.setItem('token', tokenNew)
        }
    }
})

下面来封装下这个方法,让插件帮你实现这个功能

export function piniaPlugins({store, options}: PiniaPluginContext){
    // 约定个options.saveLocal字段,来判断这个模块需不需要自动储存storage功能
    if(options.saveLocal){
        // 初始化时讲所有状态的默认值保存在Storage里
        for (const stateKey in store.$state) {
            if(localStorage.getItem(stateKey)){
                // 如果存在该字段则取出来并设置到状态里
                store.$state[stateKey] = localStorage.getItem(stateKey)
            }else{
                localStorage.setItem(stateKey, store.$state[stateKey])
            }
        }
        // 订阅状态的修改,更新
        store.$subscribe((mutation, state)=>{
            if(mutation.type === 'direct'){
                let stateKey = mutation.events.key
                localStorage.setItem(stateKey, state[stateKey])
            }else{
                mutation.events.forEach(event=>{
                    let stateKey = event.key
                    localStorage.setItem(stateKey, state[stateKey])
                })
            }
        })
    }
}

定义状态

export const useCountStore = defineStore('countTest', ()=>{
    const count = ref(0)

    return {
        count
    }
},{
    // 启用 saveLocal
    saveLocal: true
})

使用

const countStore = useCountStore()

function onClick(){
  // 这样不管哪种修改方式都能正确的设置到Storage里
  countStore.count++
  countStore.$state = {
    count: 100
  }
  countStore.$state.count++
  countStore.$patch({
    count: countStore.count+1
  })
  countStore.$patch((state)=>{
    state.count++
  })
  countStore.changeCount(100)
}