vue中使用 pinia 全局狀態(tài)管理的實(shí)現(xiàn)
與vuex的區(qū)別
去除了 mutation
選項(xiàng)。省去了復(fù)雜的disptach
和commit
流程,直接通過(guò)模塊實(shí)例調(diào)用實(shí)例的actions
中的方法即可觸發(fā)對(duì)應(yīng)action
;在組件中直接可以通過(guò)模塊實(shí)例的$patch
修改store
狀態(tài)或者通過(guò)action
來(lái)間接修改store
狀態(tài)。響應(yīng)式數(shù)據(jù)原理是proxy
,使得數(shù)據(jù)的增加或者刪除字段都具備響應(yīng)式。
安裝
yarn add pinia
引入pinia
在main.ts
中注冊(cè)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分別是管理某個(gè)狀態(tài)的模塊,index.ts用來(lái)整合這些模塊。
pinia模塊組成
state、actions、getters。
創(chuàng)建pinia模塊
對(duì)應(yīng)選項(xiàng)的含義看代碼注釋。
1.在a.js編寫(xiě)如下代碼
import {defineStore} from "pinia" export default defineStore('a',{ // a是模塊的命名空間,不能和其他模塊的一樣 state:()=>({ // state是一個(gè)函數(shù),函數(shù)返回值為管理的狀態(tài) x:0, y:0, }), })
2.在b.ts編寫(xiě)如下代碼
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中通過(guò)實(shí)例來(lái)直接修改狀態(tài) this.age=age // 在action中也可以通過(guò)實(shí)例直接調(diào)用其他action // this.print('age is be updated success') } }, getters:{ // 和vuex的getters一樣,返回一個(gè)值就行了。和computed一樣具有緩存機(jī)制 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)機(jī)
pinia的api基本都在該案例中,注釋和代碼都很容易理解,相信小伙伴們都看的懂。如果不是很明白,可以看下一章節(jié)的api講解,看懂的可以跳過(guò)api講解章節(jié)。
<script setup lang='ts'> // 引入pinia模塊 import {a as useA ,b as useB} from "./store" import {storeToRefs} from "pinia" // 模塊是一個(gè)函數(shù),函數(shù)的返回值是模塊的實(shí)例 const storeA=useA() const storeB=useB() /* 通過(guò)$patch直接修改store狀態(tài),$patch方法接收一個(gè)函數(shù),函數(shù)的參數(shù)是該模塊的狀態(tài) 在這個(gè)函數(shù)中我們可以直接修改store狀態(tài)*/ const addx=()=>{storeA.$patch((s)=>{s.x++})} const addy=()=>{storeA.$patch((s)=>{s.y++})} // 如果要解構(gòu)使用狀態(tài)需要使用該api進(jìn)行轉(zhuǎn)換,否則不具備響應(yīng)式 const {x,y}=storeToRefs(useA()) // 通過(guò)action間接修改store狀態(tài) const setAge=()=>{ // 異步action返回promise。原理也很簡(jiǎn)單,async函數(shù)的返回值是promise storeB.setAge(20).then(()=>{console.log('age is be updated success')}) } // 通過(guò) $subscribe監(jiān)聽(tīng)狀態(tài)的變更 storeB.$subscribe((c,s)=>{ // state變化時(shí)回調(diào)。有變化信息和狀態(tài)兩個(gè)參數(shù) // console.log(c) // console.log(s) },{ detached:false, // 在組件卸載時(shí)是否繼續(xù)監(jiān)聽(tīng) deep:true, // 是否深度監(jiān)聽(tīng) flush:'post', // post:組件更新后執(zhí)行;sync:始終同步觸發(fā);pre:組件更新前執(zhí)行 }) // 通過(guò)$onAction監(jiān)聽(tīng)action的調(diào)用 storeB.$onAction((c)=>{ // 當(dāng)調(diào)用action時(shí)回調(diào) // console.log(c) // c.after(()=>{console.log('after caller')}) //after的回調(diào)在該函數(shù)中最后執(zhí)行 // console.log('action') },false) // 為true時(shí),組件卸載時(shí)也監(jiān)聽(tīng)該行為 // 通過(guò)$reset重置對(duì)應(yīng)模塊的狀態(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>用戶(hù)信息:{{storeB.userInfo}}</p> <button @click="setAge">setAge</button> <button @click="reSetAge">reSetAge</button> </template>
運(yùn)行結(jié)果:
pinia模塊實(shí)例中的api講解
1.獲取模塊實(shí)例
// 引入模塊 import {a as useA ,b as useB} from "./store" // 模塊是一個(gè)函數(shù),函數(shù)的返回值是模塊的實(shí)例 const storeA=useA() const storeB=useB()
2.提供實(shí)例修改對(duì)應(yīng)模塊的狀態(tài)
i:直接修改
/* 通過(guò)$patch直接修改store狀態(tài),$patch方法接收一個(gè)函數(shù),函數(shù)的參數(shù)是該模塊的狀態(tài) 在這個(gè)函數(shù)中我們可以直接修改store狀態(tài)*/ const addx=()=>{storeA.$patch((s)=>{s.x++})} const addy=()=>{storeA.$patch((s)=>{s.y++})}
ii:間接修改
import {storeToRefs} from "pinia" // 如果要解構(gòu)使用狀態(tài)需要使用該api進(jìn)行轉(zhuǎn)換,否則不具備響應(yīng)式 const {x,y}=storeToRefs(useA())
3.狀態(tài)的解構(gòu)使用
import {storeToRefs} from "pinia" // 如果要解構(gòu)使用狀態(tài)需要使用該api進(jìn)行轉(zhuǎn)換,否則不具備響應(yīng)式 const {x,y}=storeToRefs(useA())
4.監(jiān)聽(tīng)狀態(tài)的變更
// 通過(guò) $subscribe監(jiān)聽(tīng)狀態(tài)的變更 storeB.$subscribe((c,s)=>{ // state變化時(shí)回調(diào)。有變化信息和狀態(tài)兩個(gè)參數(shù) // console.log(c) // console.log(s) },{ detached:false, // 在組件卸載時(shí)是否繼續(xù)監(jiān)聽(tīng) deep:true, // 是否深度監(jiān)聽(tīng) flush:'post', // post:組件更新后執(zhí)行 ,sync:始終同步觸發(fā) ,pre:組件更新前執(zhí)行 })
5.監(jiān)聽(tīng)action的觸發(fā)
// 通過(guò)$onAction監(jiān)聽(tīng)action的調(diào)用 storeB.$onAction((c)=>{ // 當(dāng)調(diào)用action時(shí)回調(diào) // console.log(c) // c.after(()=>{console.log('after caller')}) //after的回調(diào)在該函數(shù)中最后執(zhí)行 // console.log('action') },false) // 為true時(shí),組件卸載時(shí)也監(jiān)聽(tīng)該行為
6.重置狀態(tài)
// 通過(guò)$reset重置對(duì)應(yīng)模塊的狀態(tài) const reSetAge=()=>{ storeB.$reset() }
7.注冊(cè)插件
import {createPinia} from 'pinia' // plugin是一個(gè)函數(shù) createPinia().use(Plugin)
狀態(tài)持久化
這里需要使用到注冊(cè)插件的功能。首先在src/plugins/pinia/persistence.ts
中編寫(xiě)如下代碼
import {PiniaPluginContext} from 'pinia' import {toRaw } from 'vue' // 封裝pinia持久化插件。執(zhí)行時(shí)機(jī):store初始化時(shí),執(zhí)行次數(shù)是模塊的次數(shù) export default function(type:'localStorage' | 'sessionStorage'){ return (ctx:PiniaPluginContext)=>{ // console.log(ctx) // const {app,options,pinia,store}=ctx /* app:vue應(yīng)用 ;options:導(dǎo)出pinia模塊的選項(xiàng) pinia:pinia app ; store:pinia的store實(shí)例 */ const store= ctx.store // 每次執(zhí)行時(shí)的store是關(guān)于那個(gè)模塊的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處理過(guò)了,如果為retrun為null使用模塊的初始值, return JSON.parse(storeWay.getItem('pinia_'+store.$id) as any) } }
然后在mian.js編寫(xiě)如下代碼即可。此時(shí)刷新瀏覽器刷新時(shí),狀態(tài)是可以保持的,不會(huì)被重置。
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')
到此這篇關(guān)于vue中使用 pinia 全局狀態(tài)管理的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)vue pinia 全局狀態(tài)管理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue之input輸入框防抖debounce函數(shù)的使用方式
這篇文章主要介紹了vue之input輸入框防抖debounce函數(shù)的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11vue修改數(shù)據(jù)視圖更新原理學(xué)習(xí)
這篇文章主要為大家介紹了vue修改數(shù)據(jù)視圖更新原理學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11Vue.js結(jié)合bootstrap實(shí)現(xiàn)分頁(yè)控件
這篇文章主要為大家詳細(xì)介紹了Vue.js 合bootstrap實(shí)現(xiàn)分頁(yè)控件的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03詳解給Vue2路由導(dǎo)航鉤子和axios攔截器做個(gè)封裝
本篇文章主要介紹了詳解給Vue2路由導(dǎo)航鉤子和axios攔截器做個(gè)封裝,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-04-04vue項(xiàng)目使用$router.go(-1)返回時(shí)刷新原來(lái)的界面操作
這篇文章主要介紹了vue項(xiàng)目使用$router.go(-1)返回時(shí)刷新原來(lái)的界面操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-07-07Vue中一個(gè)組件調(diào)用其他組件的方法詳解(非父子組件)
vue中最常見(jiàn)子父組件產(chǎn)值,大家一定都很熟悉,最近項(xiàng)目中碰到非父組件中調(diào)用子組件方法的問(wèn)題,這篇文章主要給大家介紹了關(guān)于Vue中一個(gè)組件調(diào)用其他組件的方法(非父子組件),需要的朋友可以參考下2022-10-10詳解element-ui設(shè)置下拉選擇切換必填和非必填
這篇文章主要介紹了詳解element-ui設(shè)置下拉選擇切換必填和非必填,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06