vue中使用 pinia 全局狀態管理的實現
與vuex的區別
去除瞭 mutation
選項。省去瞭復雜的disptach
和commit
流程,直接通過模塊實例調用實例的actions
中的方法即可觸發對應action
;在組件中直接可以通過模塊實例的$patch
修改store
狀態或者通過action
來間接修改store
狀態。響應式數據原理是proxy
,使得數據的增加或者刪除字段都具備響應式。
安裝
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')
創建狀態目錄
在src下創建文件夾store,在store下創建文件index.ts,a.ts,b.ts。a.ts和b.ts分別是管理某個狀態的模塊,index.ts用來整合這些模塊。
pinia模塊組成
state、actions、getters。
創建pinia模塊
對應選項的含義看代碼註釋。
1.在a.js編寫如下代碼
import {defineStore} from "pinia" export default defineStore('a',{ // a是模塊的命名空間,不能和其他模塊的一樣 state:()=>({ // state是一個函數,函數返回值為管理的狀態 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中通過實例來直接修改狀態 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 }
在組件中使用該狀態機
pinia的api基本都在該案例中,註釋和代碼都很容易理解,相信小夥伴們都看的懂。如果不是很明白,可以看下一章節的api講解,看懂的可以跳過api講解章節。
<script setup lang='ts'> // 引入pinia模塊 import {a as useA ,b as useB} from "./store" import {storeToRefs} from "pinia" // 模塊是一個函數,函數的返回值是模塊的實例 const storeA=useA() const storeB=useB() /* 通過$patch直接修改store狀態,$patch方法接收一個函數,函數的參數是該模塊的狀態 在這個函數中我們可以直接修改store狀態*/ const addx=()=>{storeA.$patch((s)=>{s.x++})} const addy=()=>{storeA.$patch((s)=>{s.y++})} // 如果要解構使用狀態需要使用該api進行轉換,否則不具備響應式 const {x,y}=storeToRefs(useA()) // 通過action間接修改store狀態 const setAge=()=>{ // 異步action返回promise。原理也很簡單,async函數的返回值是promise storeB.setAge(20).then(()=>{console.log('age is be updated success')}) } // 通過 $subscribe監聽狀態的變更 storeB.$subscribe((c,s)=>{ // state變化時回調。有變化信息和狀態兩個參數 // console.log(c) // console.log(s) },{ detached:false, // 在組件卸載時是否繼續監聽 deep:true, // 是否深度監聽 flush:'post', // post:組件更新後執行;sync:始終同步觸發;pre:組件更新前執行 }) // 通過$onAction監聽action的調用 storeB.$onAction((c)=>{ // 當調用action時回調 // console.log(c) // c.after(()=>{console.log('after caller')}) //after的回調在該函數中最後執行 // console.log('action') },false) // 為true時,組件卸載時也監聽該行為 // 通過$reset重置對應模塊的狀態 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" // 模塊是一個函數,函數的返回值是模塊的實例 const storeA=useA() const storeB=useB()
2.提供實例修改對應模塊的狀態
i:直接修改
/* 通過$patch直接修改store狀態,$patch方法接收一個函數,函數的參數是該模塊的狀態 在這個函數中我們可以直接修改store狀態*/ const addx=()=>{storeA.$patch((s)=>{s.x++})} const addy=()=>{storeA.$patch((s)=>{s.y++})}
ii:間接修改
import {storeToRefs} from "pinia" // 如果要解構使用狀態需要使用該api進行轉換,否則不具備響應式 const {x,y}=storeToRefs(useA())
3.狀態的解構使用
import {storeToRefs} from "pinia" // 如果要解構使用狀態需要使用該api進行轉換,否則不具備響應式 const {x,y}=storeToRefs(useA())
4.監聽狀態的變更
// 通過 $subscribe監聽狀態的變更 storeB.$subscribe((c,s)=>{ // state變化時回調。有變化信息和狀態兩個參數 // console.log(c) // console.log(s) },{ detached:false, // 在組件卸載時是否繼續監聽 deep:true, // 是否深度監聽 flush:'post', // post:組件更新後執行 ,sync:始終同步觸發 ,pre:組件更新前執行 })
5.監聽action的觸發
// 通過$onAction監聽action的調用 storeB.$onAction((c)=>{ // 當調用action時回調 // console.log(c) // c.after(()=>{console.log('after caller')}) //after的回調在該函數中最後執行 // console.log('action') },false) // 為true時,組件卸載時也監聽該行為
6.重置狀態
// 通過$reset重置對應模塊的狀態 const reSetAge=()=>{ storeB.$reset() }
7.註冊插件
import {createPinia} from 'pinia' // plugin是一個函數 createPinia().use(Plugin)
狀態持久化
這裡需要使用到註冊插件的功能。首先在src/plugins/pinia/persistence.ts
中編寫如下代碼
import {PiniaPluginContext} from 'pinia' import {toRaw } from 'vue' // 封裝pinia持久化插件。執行時機:store初始化時,執行次數是模塊的次數 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 // 每次執行時的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初始狀態。pinia處理過瞭,如果為retrun為null使用模塊的初始值, return JSON.parse(storeWay.getItem('pinia_'+store.$id) as any) } }
然後在mian.js編寫如下代碼即可。此時刷新瀏覽器刷新時,狀態是可以保持的,不會被重置。
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 全局狀態管理的實現的文章就介紹到這瞭,更多相關vue pinia 全局狀態管理內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!