vue中使用 pinia 全局狀態(tài)管理的實現(xiàn)
與vuex的區(qū)別
去除了 mutation 選項。省去了復雜的disptach和commit流程,直接通過模塊實例調用實例的actions中的方法即可觸發(fā)對應action;在組件中直接可以通過模塊實例的$patch修改store狀態(tài)或者通過action來間接修改store狀態(tài)。響應式數(shù)據(jù)原理是proxy,使得數(shù)據(jù)的增加或者刪除字段都具備響應式。
安裝
yarn add pinia
引入pinia
在main.ts中注冊pinia插件
import {createPinia} from 'pinia' // vue3
// import {PiniaVuePlugin} from 'pinia' // vue2
const app=createApp(App)
app.use(createPinia())
app.mount('#app')
創(chuàng)建狀態(tài)目錄
在src下創(chuàng)建文件夾store,在store下創(chuàng)建文件index.ts,a.ts,b.ts。a.ts和b.ts分別是管理某個狀態(tài)的模塊,index.ts用來整合這些模塊。

pinia模塊組成
state、actions、getters。
創(chuàng)建pinia模塊
對應選項的含義看代碼注釋。
1.在a.js編寫如下代碼
import {defineStore} from "pinia"
export default defineStore('a',{ // a是模塊的命名空間,不能和其他模塊的一樣
state:()=>({ // state是一個函數(shù),函數(shù)返回值為管理的狀態(tài)
x:0,
y:0,
}),
})
2.在b.ts編寫如下代碼
import {defineStore} from "pinia"
export default defineStore('b',{
state:()=>({
name:'b',
age:18,
}),
actions:{
print(msg:string){ // 同步action
console.log(msg)
},
async setAge(newAge:number){ // 異步action
// 模擬接口
const setAgeReq=<T>(age:T)=>new Promise<T>((rel)=>{
setTimeout(()=>{rel(age)},1000)
})
const age=await setAgeReq(newAge)
// 在action中通過實例來直接修改狀態(tài)
this.age=age
// 在action中也可以通過實例直接調用其他action
// this.print('age is be updated success')
}
},
getters:{
// 和vuex的getters一樣,返回一個值就行了。和computed一樣具有緩存機制
userInfo():string{
return `name:${this.name} age:${this.age}`
}
},
})
3.在index.ts中整合所有模塊
import a from "./a"
import b from "./b"
export {
a,b
}
在組件中使用該狀態(tài)機
pinia的api基本都在該案例中,注釋和代碼都很容易理解,相信小伙伴們都看的懂。如果不是很明白,可以看下一章節(jié)的api講解,看懂的可以跳過api講解章節(jié)。
<script setup lang='ts'>
// 引入pinia模塊
import {a as useA ,b as useB} from "./store"
import {storeToRefs} from "pinia"
// 模塊是一個函數(shù),函數(shù)的返回值是模塊的實例
const storeA=useA()
const storeB=useB()
/* 通過$patch直接修改store狀態(tài),$patch方法接收一個函數(shù),函數(shù)的參數(shù)是該模塊的狀態(tài)
在這個函數(shù)中我們可以直接修改store狀態(tài)*/
const addx=()=>{storeA.$patch((s)=>{s.x++})}
const addy=()=>{storeA.$patch((s)=>{s.y++})}
// 如果要解構使用狀態(tài)需要使用該api進行轉換,否則不具備響應式
const {x,y}=storeToRefs(useA())
// 通過action間接修改store狀態(tài)
const setAge=()=>{
// 異步action返回promise。原理也很簡單,async函數(shù)的返回值是promise
storeB.setAge(20).then(()=>{console.log('age is be updated success')})
}
// 通過 $subscribe監(jiān)聽狀態(tài)的變更
storeB.$subscribe((c,s)=>{ // state變化時回調。有變化信息和狀態(tài)兩個參數(shù)
// console.log(c)
// console.log(s)
},{
detached:false, // 在組件卸載時是否繼續(xù)監(jiān)聽
deep:true, // 是否深度監(jiān)聽
flush:'post', // post:組件更新后執(zhí)行;sync:始終同步觸發(fā);pre:組件更新前執(zhí)行
})
// 通過$onAction監(jiān)聽action的調用
storeB.$onAction((c)=>{ // 當調用action時回調
// console.log(c)
// c.after(()=>{console.log('after caller')}) //after的回調在該函數(shù)中最后執(zhí)行
// console.log('action')
},false) // 為true時,組件卸載時也監(jiān)聽該行為
// 通過$reset重置對應模塊的狀態(tài)
const reSetAge=()=>{
storeB.$reset()
}
</script>
<template>
<h3>模塊a</h3>
<p>({{storeA.x}},{{storeA.y}})</p>
<button @click="addx">x++</button>
<button @click="addy">y++</button>
<h3>模塊b</h3>
<p>用戶信息:{{storeB.userInfo}}</p>
<button @click="setAge">setAge</button>
<button @click="reSetAge">reSetAge</button>
</template>
運行結果:

pinia模塊實例中的api講解
1.獲取模塊實例
// 引入模塊
import {a as useA ,b as useB} from "./store"
// 模塊是一個函數(shù),函數(shù)的返回值是模塊的實例
const storeA=useA()
const storeB=useB()
2.提供實例修改對應模塊的狀態(tài)
i:直接修改
/* 通過$patch直接修改store狀態(tài),$patch方法接收一個函數(shù),函數(shù)的參數(shù)是該模塊的狀態(tài)
在這個函數(shù)中我們可以直接修改store狀態(tài)*/
const addx=()=>{storeA.$patch((s)=>{s.x++})}
const addy=()=>{storeA.$patch((s)=>{s.y++})}
ii:間接修改
import {storeToRefs} from "pinia"
// 如果要解構使用狀態(tài)需要使用該api進行轉換,否則不具備響應式
const {x,y}=storeToRefs(useA())
3.狀態(tài)的解構使用
import {storeToRefs} from "pinia"
// 如果要解構使用狀態(tài)需要使用該api進行轉換,否則不具備響應式
const {x,y}=storeToRefs(useA())
4.監(jiān)聽狀態(tài)的變更
// 通過 $subscribe監(jiān)聽狀態(tài)的變更
storeB.$subscribe((c,s)=>{ // state變化時回調。有變化信息和狀態(tài)兩個參數(shù)
// console.log(c)
// console.log(s)
},{
detached:false, // 在組件卸載時是否繼續(xù)監(jiān)聽
deep:true, // 是否深度監(jiān)聽
flush:'post', // post:組件更新后執(zhí)行 ,sync:始終同步觸發(fā) ,pre:組件更新前執(zhí)行
})
5.監(jiān)聽action的觸發(fā)
// 通過$onAction監(jiān)聽action的調用
storeB.$onAction((c)=>{ // 當調用action時回調
// console.log(c)
// c.after(()=>{console.log('after caller')}) //after的回調在該函數(shù)中最后執(zhí)行
// console.log('action')
},false) // 為true時,組件卸載時也監(jiān)聽該行為
6.重置狀態(tài)
// 通過$reset重置對應模塊的狀態(tài)
const reSetAge=()=>{
storeB.$reset()
}
7.注冊插件
import {createPinia} from 'pinia'
// plugin是一個函數(shù)
createPinia().use(Plugin)
狀態(tài)持久化
這里需要使用到注冊插件的功能。首先在src/plugins/pinia/persistence.ts中編寫如下代碼
import {PiniaPluginContext} from 'pinia'
import {toRaw } from 'vue'
// 封裝pinia持久化插件。執(zhí)行時機:store初始化時,執(zhí)行次數(shù)是模塊的次數(shù)
export default function(type:'localStorage' | 'sessionStorage'){
return (ctx:PiniaPluginContext)=>{
// console.log(ctx)
// const {app,options,pinia,store}=ctx
/*
app:vue應用 ;options:導出pinia模塊的選項
pinia:pinia app ; store:pinia的store實例
*/
const store= ctx.store // 每次執(zhí)行時的store是關于那個模塊的store
const storeWay=type==='localStorage'?localStorage:sessionStorage
// console.log(store)
store.$subscribe(()=>{
// console.log(toRaw(store.$state))
storeWay.setItem('pinia_'+store.$id,JSON.stringify(toRaw(store.$state)))
},{deep:true})
// return的值為store初始狀態(tài)。pinia處理過了,如果為retrun為null使用模塊的初始值,
return JSON.parse(storeWay.getItem('pinia_'+store.$id) as any)
}
}
然后在mian.js編寫如下代碼即可。此時刷新瀏覽器刷新時,狀態(tài)是可以保持的,不會被重置。
import { createApp} from 'vue'
import App from './App.vue'
import {createPinia} from 'pinia'
// import {PiniaVuePlugin} from 'pinia' // vue2
import persistence from "./plugins/pinia/persistence"
const app=createApp(App)
// app.use(createPinia().use(persistence('sessionStorage'))) //sessionStorage方式持久化
app.use(createPinia().use(persistence('localStorage'))) //localStorage方式持久化
app.mount('#app')
到此這篇關于vue中使用 pinia 全局狀態(tài)管理的實現(xiàn)的文章就介紹到這了,更多相關vue pinia 全局狀態(tài)管理內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
vue之input輸入框防抖debounce函數(shù)的使用方式
這篇文章主要介紹了vue之input輸入框防抖debounce函數(shù)的使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11
vue項目使用$router.go(-1)返回時刷新原來的界面操作
這篇文章主要介紹了vue項目使用$router.go(-1)返回時刷新原來的界面操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07

