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

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

二、使用Pinia
1. 安裝
npm install pinia
2. 創(chuàng)建Pinia
創(chuàng)建stores文件夾,并在其中創(chuàng)建個(gè)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 :
- 一個(gè) Store (如 Pinia)是一個(gè)實(shí)體,它會(huì)持有為綁定到你組件樹的狀態(tài)和業(yè)務(wù)邏輯,也就是保存了全局的狀態(tài)
- 它有點(diǎn)像始終存在,并且每個(gè)人都可以讀取和寫入的組件
- 你可以在你的應(yīng)用程序中定義任意數(shù)量的Store來(lái)管理你的狀態(tài)
Store有三個(gè)核心概念 :
- state、getters、actions
- 等同于組件的data、computed、methods
- 一旦 store 被實(shí)例化,可以直接在 store 上面訪問 state、getters 和 actions 中定義的任何屬性
2. 創(chuàng)建
定義一個(gè)Store :
- Store 是使用 defineStore() 定義
- 并且它需要一個(gè)唯一名稱,作為第一個(gè)參數(shù)傳遞
在stores文件夾創(chuàng)建 counter.js 文件
// 1, 導(dǎo)入
import { defineStore } from 'pinia';
// 2. 創(chuàng)建一個(gè)store
/**
* 第一個(gè)參數(shù) : 唯一的名稱
* 第二個(gè)參數(shù) : 傳入配置
* 返回值 : 返回一個(gè)函數(shù),調(diào)用這個(gè)函數(shù),即可拿到當(dāng)前store
*/
const userCounterStore = defineStore('counterStore', {
state: () => ({
count: 66
})
});
export default userCounterStore;3. 使用
<template>
<div class="app">App 頁(yè)面</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)建一個(gè)store
/**
* 第一個(gè)參數(shù) : 唯一的名稱
* 第二個(gè)參數(shù) : 傳入配置
* 返回值 : 返回一個(gè)函數(shù),調(diào)用這個(gè)函數(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)來(lá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 方法
允許同時(shí)應(yīng)用多個(gè)更改
// 監(jiān)聽點(diǎn)擊
const changCount = () => {
// 一起更改數(shù)據(jù)
counterStore.$patch({
count: 99,
name: 'star',
// 如果輸入新增的屬性,沒有用噠!
buy: ref('abvc')
});
console.log(counterStore);
};5. 替換State
可以通過將其 $state 屬性設(shè)置為新對(duì)象來(lái)替換 Store 的整個(gè)狀態(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來(lái)拿
return this.doubleCount;
}
}3. getters支持返回一個(gè)函數(shù)
可以用來(lái)傳遞參數(shù)到getters
代碼
getters: {
doubleCount(state) {
return this.count * 2;
},
formatName() {
// 返回一個(gè)函數(shù),可以傳遞參數(shù)進(jìn)來(lái)
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í)傳遞過來(lái)的參數(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. 請(qǐng)求
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)榉祷氐臅r(shí)promise,所以可以在then中拿到數(shù)據(jù)
console.log(res);
});
</script>總結(jié)
到此這篇關(guān)于Vue3之Pinia狀態(tài)管理的文章就介紹到這了,更多相關(guān)Vue3 Pinia狀態(tài)管理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺談vue+webpack項(xiàng)目調(diào)試方法步驟
本篇文章主要介紹了淺談vue+webpack項(xiàng)目調(diào)試方法步驟,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2017-09-09
vue.js 表格分頁(yè)ajax 異步加載數(shù)據(jù)
Vue.js通過簡(jiǎn)潔的API提供高效的數(shù)據(jù)綁定和靈活的組件系統(tǒng).這篇文章主要介紹了vue.js 表格分頁(yè)ajax 異步加載數(shù)據(jù)的相關(guān)資料,需要的朋友可以參考下2016-10-10
laravel5.4+vue+element簡(jiǎn)單搭建的示例代碼
本篇文章主要介紹了laravel5.4+vue+element簡(jiǎn)單搭建的示例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
Vue數(shù)據(jù)變了但頁(yè)面沒有變的幾種情況及解決方法
如果,你發(fā)現(xiàn)自己需要在Vue中做一次強(qiáng)制更新,99.99%的情況,是你在某個(gè)地方做錯(cuò)了事,本文給大家就介紹了Vue數(shù)據(jù)變了,但頁(yè)面沒有變的幾種情況及解決方法,并通過代碼示例介紹的非常詳細(xì),需要的朋友可以參考下2024-08-08
利用vue + element實(shí)現(xiàn)表格分頁(yè)和前端搜索的方法
眾所周知Element 是一套 Vue.js 后臺(tái)組件庫(kù),它能夠幫助你更輕松更快速地開發(fā)后臺(tái)項(xiàng)目。下面這篇文章主要給大家介紹了關(guān)于利用vue + element實(shí)現(xiàn)表格分頁(yè)和前端搜索的相關(guān)資料,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-12-12
Vue.js?rules校驗(yàn)規(guī)則舉例詳解
Vue表單校驗(yàn)規(guī)則(rules)是一種用于驗(yàn)證表單數(shù)據(jù)的對(duì)象,它通常用于Vue.js框架中的表單組件中,可以在表單提交前進(jìn)行數(shù)據(jù)驗(yàn)證,這篇文章主要給大家介紹了關(guān)于Vue.js?rules校驗(yàn)規(guī)則的相關(guān)資料,需要的朋友可以參考下2024-02-02

