Vue使用Pinia輕松實(shí)現(xiàn)狀態(tài)管理
前言
pinia,一個基于Vue3的狀態(tài)管理庫,它可以幫助開發(fā)人員管理Vue應(yīng)用程序的狀態(tài),Pinia使用Vue3的Composition API提供了更簡單,靈活的狀態(tài)管理方式,通過創(chuàng)建store來管理應(yīng)用程序的狀態(tài),還提供了插件和工具來幫助開發(fā)人員更輕松的使用它。
Pinia對比VueX
之前我們在vue2的時候使用的狀態(tài)管理庫是VueX,在Vue3中想使用VueX,需要使用到VueX4版本,而在Vue3組合式API下設(shè)計(jì)了全新的狀態(tài)管理庫:Vuex5,也就是Pinia(已經(jīng)被納入官方了)
那Pinia相比VueX有什么優(yōu)勢呢?

在當(dāng)時pinia的作者就作出了這么一個提案:
- pinia都支持在vue2和vue3中使用
- 在vuex想修改數(shù)據(jù)狀態(tài)需要mutations,而pinia去掉了mutations,只有state,getters和actions。修改數(shù)據(jù)狀態(tài)直接在actions里操作,pinia推崇使用類似于 JavaScript 對象的方式來更新狀態(tài),即直接對 state 進(jìn)行修改,可以減少代碼量,并且降低了出錯的可能性
- pinia中沒有嵌套模塊,在vuex中我們可能會用到大量的模塊,一層套一層,使?fàn)顟B(tài)管理變得復(fù)雜,也有可能會造成命名沖突,在Composition API下pinia中可以定義多個store,然后將多個store組合在一起,變得更加靈活
- 完整的TypeScript支持,vuex對ts的類型檢查,類型推斷和泛型的支持都不太友好,模塊命名空間的支持也不夠完善
除此之外兩者的api都是相同的,使用的方式也是相同的,關(guān)于vuex的使用可以看看之前寫的vuex文章
Pinia的使用
安裝pinia
使用pinia需要先安裝,可以通過yarn或者npm安裝
yarn add pinia
# or with npm
npm install pinia
在vue2中使用,你還需要安裝一個插件并pinia在應(yīng)用程序的根目錄注入創(chuàng)建的,如果vue版本<2.7,還需要安裝 composition api: @vue/composition-api

安裝完之后在入口文件引入pinia的createPinia方法并調(diào)用得到pinia的實(shí)例,然后掛載到vue實(shí)例上
import { createApp } from "vue";
import App from "./App.vue";
import { createPinia } from "pinia";
//創(chuàng)建pinia實(shí)例
const pinia = createPinia();
const app = createApp(App);
//掛載到vue實(shí)例上
app.use(pinia);
app.mount("#app");定義store容器
在src目錄下創(chuàng)建store目錄來存放pinia容器相關(guān)代碼,在里面新建了一個index.ts文件,在index.ts文件里首先要定義一個容器,定義容器使用defineStore來定義,主要接收兩個參數(shù),一個是容器的名字(唯一),另一個是容器的對象,最后將容器導(dǎo)出,就可以在組件中使用了
import { defineStore } from "pinia";
export const useTestStore = defineStore("test", {
/**
* 類似組件中的data,存儲全局狀態(tài)
* 必須是箭頭函數(shù),避免數(shù)據(jù)狀態(tài)污染
*/
state: () => {
return {
message: "hello world",
count:0,
};
},
/**
* 類似組件中的computed
*/
getters: {},
/**
* 類似組件中的methods,封裝業(yè)務(wù)邏輯,修改state
*/
actions: {},
});在組件中導(dǎo)入并使用容器
state的使用
在組件中導(dǎo)入容器并且調(diào)用,得到容器的實(shí)例,就可以直接使用state里的數(shù)據(jù)或者在模板中展示
<script setup lang="ts">
import { useTestStore } from "./store";
const store = useTestStore();
</script>
<template>
<div>{{ store.message }}</div>
</template>
<style scoped>
</style>
也可以使用解構(gòu)的方式拿到和使用數(shù)據(jù),但是這樣拿到的數(shù)據(jù)不是響應(yīng)式的,修改的時候頁面上是不會發(fā)生變化的
<script setup lang="ts">
import { useTestStore } from "./store";
const store = useTestStore();
//解構(gòu)state
const { message, count } = store;
const countAdd = () => {
store.count++;
};
</script>
<template>
<div>
<div>{{ store.message }}</div>
<div>{{ store.count }}</div>
<hr />
<div>{{ "解構(gòu)后:" + message }}</div>
<div>{{ "解構(gòu)后:" + count }}</div>
<button @click="countAdd">count++</button>
</div>
</template>
<style scoped>
</style>
針對這種情況解決的辦法就是解構(gòu)的時候使用pinia的storeToRefs方法將實(shí)例包裹住,state里的數(shù)據(jù)就變成響應(yīng)式的了
import { storeToRefs } from "pinia";
//解構(gòu)state,對state里的數(shù)據(jù)做了reactive處理
const { message, count } = storeToRefs(store);
狀態(tài)的更新和actions的使用
在組件里修改state的狀態(tài)的時候有三種方式:
- 直接修改
- $patch直接修改
- $patch通過函數(shù)修改
const countAdd = () => {
// 直接修改
store.count++;
store.message = 'hello pinia'
// 修改多個數(shù)據(jù) $patch批量修改
store.$patch({
count: store.count + 1,
message: "hello pinia",
});
// $patch 函數(shù)(推薦)
store.$patch(state=>{
state.count++
state.message = "hello pinia"
})
};也可以通過actions處理,在actions定義一個方法,通過this訪問當(dāng)前實(shí)例拿到state里的數(shù)據(jù),就像vue2的options API一樣在methods里拿data里的數(shù)據(jù)
// store
actions: {
handleChangeState() {
this.message = "hello pinia";
this.count++;
},
},
//component
const countAdd = () => {
store.handleChangeState();
};也可以在調(diào)用actions里的方法的時候傳遞參數(shù)
// store
actions: {
handleChangeState(num?: number) {
this.count += num ?? 0;
},
},
//component
const countAdd = () => {
store.handleChangeState(10);
};getters的使用
getters類似組件中的computed,接收一個state參數(shù),這個state就是容器里的state狀態(tài)對象,當(dāng)依賴的state發(fā)生變化的時候pinia就會自動更新getters的值,而且getters具有默認(rèn)的緩存機(jī)制
如果一個getter所依賴的state沒有發(fā)生變化,那么就返回上一次計(jì)算的結(jié)果,而不會重新計(jì)算,顯著提高了性能
// getters
getters: {
// typescript自動推導(dǎo)返回值類型
countMUL10(state) {
console.log("getter被調(diào)用了");
return state.count * 10;
},
// or手動指定返回值類型
countMUL10():number {
console.log("getter被調(diào)用了");
return this.count * 10;
},
},
//component
<template>
<div>
<div>{{ store.count }}</div>
// 調(diào)用多次
<div>{{ store.countMUL10 }}</div>
<div>{{ store.countMUL10 }}</div>
<div>{{ store.countMUL10 }}</div>
<button @click="countAdd">count++</button>
</div>
</template>
store容器調(diào)用另一個store容器
如果你想在一個Store中使用另一個Store,就和在組件中使用store一樣操作就可以了
import { defineStore } from "pinia";
//導(dǎo)入一個store容器
import { useTestStore } from ".";
export const useLoginStore = defineStore("login", {
state: () => {
return {};
},
getters: {},
actions: {
handlerOtherStore() {
//得到store實(shí)例,調(diào)用實(shí)例里的方法
const testStore = useTestStore();
testStore.handleChangeState(10);
},
},
});以上就是Vue使用Pinia輕松實(shí)現(xiàn)狀態(tài)管理的詳細(xì)內(nèi)容,更多關(guān)于Vue Pinia的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解Vue實(shí)現(xiàn)鏈接生成二維碼并支持下載
在現(xiàn)代 Web 應(yīng)用中,快速分享鏈接是一項(xiàng)常見需求,二維碼作為一種簡潔的分享方式,受到了廣泛歡迎,所以本文將介紹如何使用 Vue 純前端技術(shù)實(shí)現(xiàn)動態(tài)生成鏈接二維碼的方法,需要的可以參考下2024-03-03
區(qū)分vue-router的hash和history模式
這篇文章主要介紹了區(qū)分vue-router的hash和history模式,幫助大家更好的理解和學(xué)習(xí)vue路由,感興趣的朋友可以了解下2020-10-10
VueJS實(shí)現(xiàn)用戶管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了VueJS實(shí)現(xiàn)用戶管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-05-05
vue?router權(quán)限管理實(shí)現(xiàn)不同角色顯示不同路由
本文主要介紹了vue?router權(quán)限管理實(shí)現(xiàn)不同角色顯示不同路由,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03
vue使用Google地圖的實(shí)現(xiàn)示例代碼
這篇文章主要介紹了vue使用Google地圖的實(shí)現(xiàn)示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-12-12

