帶你熟練掌握Vue3之Pinia狀態(tài)管理
一、概念
1. Pinia => Pinia
Pinia(發(fā)音為/pi?nj?/,如英語中的“peenya”)是最接近piña(西班牙語中的菠蘿)的詞
- Pinia開始于大概2019年,最初是作為一個實(shí)驗(yàn)為Vue重新設(shè)計(jì)狀態(tài)管理,讓它用起來像組合式API(Composition API)
- 從那時到現(xiàn)在,最初的設(shè)計(jì)原則依然是相同的,并且目前同時兼容Vue2、Vue3,也并不要求你使用Composition API
- Pinia本質(zhì)上依然是一個狀態(tài)管理的庫,用于跨組件、頁面進(jìn)行狀態(tài)共享(這點(diǎn)和Vuex、Redux一樣)

2. Pinia和Vuex的對比
01 - 不是已經(jīng)有Vuex了嗎?為什么還要用Pinia
- Pinia 最初是為了探索 Vuex 的下一次迭代會是什么樣子,結(jié)合了 Vuex 5 核心團(tuán)隊(duì)討論中的許多想法
- 最終,團(tuán)隊(duì)意識到Pinia已經(jīng)實(shí)現(xiàn)了Vuex5中大部分內(nèi)容,所以最終決定用Pinia來替代Vuex
- 與 Vuex 相比,Pinia 提供了一個更簡單的 API,具有更少的儀式,提供了 Composition-API 風(fēng)格的 API
- 最重要的是,在與 TypeScript 一起使用時具有可靠的類型推斷支持
02 - 和Vuex相比,Pinia有很多的優(yōu)勢
- mutations 不再存在
- 他們經(jīng)常被認(rèn)為是 非常 冗長
- 他們最初帶來了 devtools 集成,但這不再是問題
- 更友好的TypeScript支持,Vuex之前對TS的支持很不友好
- 不再有modules的嵌套結(jié)構(gòu)
- 可以靈活使用每一個store,它們是通過扁平化的方式來相互使用的
- 也不再有命名空間的概念,不需要記住它們的復(fù)雜關(guān)系
- Pinia的store中的 getters、actions 可以使用this,this代表當(dāng)前sotre對象

二、使用Pinia
1. 安裝
npm install pinia
2. 創(chuàng)建Pinia
創(chuàng)建stores文件夾,并在其中創(chuàng)建個index.js
// 1. 導(dǎo)入
import { createPinia } from 'pinia';
// 2. 創(chuàng)建
const pinia = createPinia();
// 3. 導(dǎo)出
export default pinia;3. 在main.js中引入
import { createApp } from 'vue';
import App from './App.vue';
// 1. 導(dǎo)入
import pinia from './stores';
// 2. use一下
createApp(App).use(pinia).mount('#app');三、Store
1. 概念
Store :
- 一個 Store (如 Pinia)是一個實(shí)體,它會持有為綁定到你組件樹的狀態(tài)和業(yè)務(wù)邏輯,也就是保存了全局的狀態(tài)
- 它有點(diǎn)像始終存在,并且每個人都可以讀取和寫入的組件
- 你可以在你的應(yīng)用程序中定義任意數(shù)量的Store來管理你的狀態(tài)
Store有三個核心概念 :
- state、getters、actions
- 等同于組件的data、computed、methods
- 一旦 store 被實(shí)例化,可以直接在 store 上面訪問 state、getters 和 actions 中定義的任何屬性
2. 創(chuàng)建
定義一個Store :
- Store 是使用 defineStore() 定義
- 并且它需要一個唯一名稱,作為第一個參數(shù)傳遞
在stores文件夾創(chuàng)建 counter.js 文件
// 1, 導(dǎo)入
import { defineStore } from 'pinia';
// 2. 創(chuàng)建一個store
/**
* 第一個參數(shù) : 唯一的名稱
* 第二個參數(shù) : 傳入配置
* 返回值 : 返回一個函數(shù),調(diào)用這個函數(shù),即可拿到當(dāng)前store
*/
const userCounterStore = defineStore('counterStore', {
state: () => ({
count: 66
})
});
export default userCounterStore;3. 使用
<template>
<div class="app">App 頁面</div>
<h2>1. counterStore : {{ counterStore.count }}</h2>
<h2>2. toRefs : {{ aCount }}</h2>
<h2>3. storeToRefs : {{ bCount }}</h2>
<button @click="changCount">改變count</button>
</template>
<script setup>
import { toRefs } from 'vue';
import { storeToRefs } from 'pinia';
// 1. 導(dǎo)入該函數(shù)
import userCounterStore from '@/stores/module/counter';
// 2. 調(diào)用,獲得store
const counterStore = userCounterStore();
// 3. 拿到state值
/**
* 注意 : 直接解構(gòu)可以拿到值,但并不是響應(yīng)式的了
* 1. 使用 toRefs
* 2. 使用pinia提供的 storeToRefs
*/
// toRefs
const { count: aCount } = toRefs(counterStore);
// storeToRefs
const { count: bCount } = storeToRefs(counterStore);
// 監(jiān)聽點(diǎn)擊
const changCount = () => {
// 可以直接操作?。?!
counterStore.count++;
};
</script>4. 效果

四、核心概念State
1. 定義State
// 1, 導(dǎo)入
import { defineStore } from 'pinia';
// 2. 創(chuàng)建一個store
/**
* 第一個參數(shù) : 唯一的名稱
* 第二個參數(shù) : 傳入配置
* 返回值 : 返回一個函數(shù),調(diào)用這個函數(shù),即可拿到當(dāng)前store
*/
const userCounterStore = defineStore('counterStore', {
state: () => ({
count: 66,
name: 'coder',
age: 19
})
});
export default userCounterStore;2. 讀取寫入State
默認(rèn)情況下,可以通過 store 實(shí)例訪問狀態(tài)來直接讀取和寫入狀態(tài)
<script setup>
import Home from './views/Home.vue';
// 1. 導(dǎo)入該函數(shù)
import { toRefs } from 'vue';
import { storeToRefs } from 'pinia';
import userCounterStore from '@/stores/module/counter';
// 2. 調(diào)用,獲得store
const counterStore = userCounterStore();
// 3. 拿到state值
const { count } = storeToRefs(counterStore);
// 監(jiān)聽點(diǎn)擊
const changCount = () => {
// 1. 讀取
console.log(counterStore.count);
// 2. 寫入
counterStore.count++;
};
</script>3. 重置State
可以通過調(diào)用 store 上的 $reset() 方法將狀態(tài) 重置 到其初始值
// 重置
const resetState = () => {
// 回到初始值
counterStore.$reset();
};4. 改變State
除了直接用 store.counter++ 修改 store,還可以調(diào)用 $patch 方法
允許同時應(yīng)用多個更改
// 監(jiān)聽點(diǎn)擊
const changCount = () => {
// 一起更改數(shù)據(jù)
counterStore.$patch({
count: 99,
name: 'star',
// 如果輸入新增的屬性,沒有用噠!
buy: ref('abvc')
});
console.log(counterStore);
};5. 替換State
可以通過將其 $state 屬性設(shè)置為新對象來替換 Store 的整個狀態(tài)

五、核心概念Getters
1. 基本使用
代碼
const userCounterStore = defineStore('counterStore', {
state: () => ({
count: 66,
name: 'coder',
age: 19
}),
getters: {
// 1. 定義getterts
doubleCount(state) {
// 2. 通過state參數(shù)拿到count
console.log(state.count);
// 3. 通過this拿到參數(shù)
console.log(this.count);
}
}
});使用
<template>
<div>home</div>
<h2>count : {{ counterStore.count }}</h2>
<hr />
<h2>count : {{ counterStore.doubleCount }}</h2>
<button @click="changCount">改變count</button>
</template>
<script setup>
import { toRefs } from 'vue';
import userCounterStore from '@/stores/module/counter';
// 1. 獲取store
const counterStore = userCounterStore();
// 2. 解構(gòu),變成響應(yīng)式
const { doubleCount } = toRefs(counterStore);
console.log(doubleCount);
// 監(jiān)聽點(diǎn)擊
const changCount = () => {
// 3. 改變store
counterStore.count++;
// 4. 輸出
console.log(doubleCount.value);
};
</script>2. 在getter中使用其他的getter
getters: {
doubleCount(state) {
return this.count * 2;
},
othersGetter() {
// 通過this來拿
return this.doubleCount;
}
}3. getters支持返回一個函數(shù)
可以用來傳遞參數(shù)到getters
代碼
getters: {
doubleCount(state) {
return this.count * 2;
},
formatName() {
// 返回一個函數(shù),可以傳遞參數(shù)進(jìn)來
return (lastName) => {
return this.name + lastName;
};
}
}使用
<template>
<h2>{{ counterStore.formatName('123') }}</h2>
<button @click="changCount">改變count</button>
</template>
<script setup>
import { toRefs } from 'vue';
import userCounterStore from '@/stores/module/counter';
// 1. 獲取store
const counterStore = userCounterStore();
// 2. 解構(gòu),變成響應(yīng)式
const { formatName } = toRefs(counterStore);
const changCount = () => {
// 3. 使用函數(shù)
console.log(formatName.value('444'));
// 也可以直接使用,看情況而定
counterStore.formatName('123')
};
</script>4. getters使用別的store中的數(shù)據(jù)
導(dǎo)入其他的store,使用即可,很方便
userOtherStore(){
// 1. 導(dǎo)入其他soter
const otherStore = userOtherStore()
// 2. 拿到數(shù)據(jù) ....
otherStore.getters()
}六、核心概念A(yù)ctions
actions => 非常適合定義業(yè)務(wù)邏輯
1. 基本使用
代碼
const userCounterStore = defineStore('counterStore', {
state: () => ({
count: 66,
name: 'coder',
age: 19
}),
actions: {
increment() {
this.count++;
},
// 這里的參數(shù)指調(diào)用時傳遞過來的參數(shù)
incrementNum(num) {
this.count += num;
}
}
});使用
<script setup>
import userCounterStore from '@/stores/module/counter';
// 1. 獲取store
const counterStore = userCounterStore();
// 2. 解構(gòu)
const { increment, incrementNum } = counterStore;
// 3. 調(diào)用
increment();
incrementNum(33);
</script>2. 異步操作
代碼
const userCounterStore = defineStore('counterStore', {
state: () => ({
arrList: []
}),
actions: {
async fetchDataList() {
// 1. 請求
const res = await fetch('http:xxxxx');
const data = await res.json();
this.arrList = data.list;
// 2. 返回值,相當(dāng)于 return Promise.resolve(data)
return data;
}
}
});使用
<script setup>
import userCounterStore from '@/stores/module/counter';
// 1. 獲取store
const counterStore = userCounterStore();
// 2. 解構(gòu)
const { fetchDataList } = counterStore;
// 3. 調(diào)用
fetchDataList().then((res) => {
// 因?yàn)榉祷氐臅rpromise,所以可以在then中拿到數(shù)據(jù)
console.log(res);
});
</script>總結(jié)
到此這篇關(guān)于Vue3之Pinia狀態(tài)管理的文章就介紹到這了,更多相關(guān)Vue3 Pinia狀態(tài)管理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue中router.beforeEach與beforeRouteEnter的區(qū)別及說明
這篇文章主要介紹了Vue中router.beforeEach與beforeRouteEnter的區(qū)別及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10
Vue前端導(dǎo)出Excel文件的詳細(xì)實(shí)現(xiàn)方案
在開發(fā)后臺管理系統(tǒng)的時候,很多地方都要用到導(dǎo)出excel表格,比如將table中的數(shù)據(jù)導(dǎo)出到本地,下面這篇文章主要給大家介紹了關(guān)于Vue導(dǎo)出Excel文件的相關(guān)資料,需要的朋友可以參考下2021-09-09
vue解決使用$http獲取數(shù)據(jù)時報(bào)錯的問題
今天小編就為大家分享一篇vue解決使用$http獲取數(shù)據(jù)時報(bào)錯的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-10-10
詳解VUE 對element-ui中的ElTableColumn擴(kuò)展
本篇文章主要介紹了詳解VUE 對element-ui中的ElTableColumn擴(kuò)展,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-03-03
Vue通過配置WebSocket并實(shí)現(xiàn)群聊功能
本篇文章將與各位開發(fā)者分享下 vue-native-websocket 庫的使用以及配置,通過實(shí)例代碼給大家分享Vue通過配置WebSocket并實(shí)現(xiàn)群聊功能,需要的朋友可以參考下2019-12-12
Vue.js計(jì)算機(jī)屬性computed和methods方法詳解
這篇文章主要為大家詳細(xì)介紹了Vue.js計(jì)算機(jī)屬性computed和methods方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-10-10
VUE引入騰訊地圖并實(shí)現(xiàn)軌跡動畫的詳細(xì)步驟
這篇文章主要介紹了VUE引入騰訊地圖并實(shí)現(xiàn)軌跡動畫,引入步驟大概是在 html 中通過引入 script 標(biāo)簽加載API服務(wù),結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09

