Vue3之狀態(tài)管理器(Pinia)詳解及使用方式
注意:本文項(xiàng)目使用腳手架為 Vite;
1. 前言
Pinia 對(duì)比 Vuex
- Pinia 同時(shí)支持 Vue2 以及 Vue3 ,這讓同時(shí)使用兩個(gè)版本的小伙伴更容易上手;
- Pinia 中只存在 State,getter,action,剔除掉了 Vuex 中的 Mutation 及 Module;
- Pinia 中的 action 可同時(shí)支持同步任務(wù)、異步任務(wù);
- 更友好的支持了 TypeScript ,無(wú)需創(chuàng)建自定義復(fù)雜包裝器來支持 TypeScript,所有內(nèi)容都是類型化的,并且 API 的設(shè)計(jì)方式盡可能利用 TS 類型推斷;
- Pinia 在修改狀態(tài)的時(shí)候不需要通過其他 api,如:vuex 需通過 commit,dispatch 來修改,所以在語(yǔ)法上比 vuex 更容易理解和使用靈活;
- 由于去除掉了 Module ,無(wú)需再創(chuàng)建各個(gè)模塊嵌套了。Vuex 中,如果數(shù)據(jù)過多,通常會(huì)通過劃分模塊來進(jìn)行管理,而 Pinia 中,每個(gè) Store 都是獨(dú)立的,互不影響;
- 支持服務(wù)端渲染;
2. 安裝及引入
yarn add pinia // 或者使用 npm npm install pinia
安裝完 Pinia 包之后,需要在 main.js 文件中導(dǎo)入 createPinia 函數(shù)并將 Pinia 插件與 Vue 應(yīng)用程序綁定:
import { createApp } from 'vue';
import App from './App.vue';
// 引入 createPinia 函數(shù)
import { createPinia } from 'pinia';
const app = createApp(App)
// 使用 createPinia() 來創(chuàng)建 Pinia(根存儲(chǔ)),并應(yīng)用到整個(gè)應(yīng)用中
app.use(createPinia());
app.mount('#app');
使用 createPinia() 函數(shù)創(chuàng)建并初始化 Pinia 插件實(shí)例,將其與 Vue 應(yīng)用程序綁定使用 app.use(pinia)。
至此,我們就可以使用Pinia 來管理 Vue 應(yīng)用程序的狀態(tài)了。
最后,在 src 文件下創(chuàng)建一個(gè) store 文件夾,并添加 store.js 文件。
3. Pinia的使用Store
Store
是使用 defineStore() 定義的,并且它需要一個(gè)唯一名稱,作為第一個(gè)參數(shù)傳遞。
這個(gè)名字 ,也被用作 id 是必須傳入的, Pinia 將用它來連接 store 和 devtools。
將返回的函數(shù)命名為 use… 是跨可組合項(xiàng)的約定,以使其符合使用習(xí)慣。
State
State 是 store 中存儲(chǔ)數(shù)據(jù)的地方。
通過定義 State,可以在 store 的任何位置訪問和修改數(shù)據(jù)。
// store/store.js
import { defineStore } from 'pinia';
export const useMainStore = defineStore('main',{
state: () => {
return {
count:0
}
}
})
// views/home.vue
<template>
<div class="count">state:{{mainStore.count}}</div>
<div class="btnWrap">
<button @click="resetStore">重 置</button>
</div>
</template>
<script setup>
import {useMainStore} from '@/store/store.js';
const mainStore = useMainStore();
console.log(mainStore.count) // 0
const resetStore = () => {
mainStore.$reset()
}
</script>
效果:

Getters
Getter 用來獲取從 state 派生的數(shù)據(jù),類似于 Vue 組件中的 computed 計(jì)算屬性。
可通過 defineStore() 中的 getters 屬性來定義它們。
推薦使用箭頭函數(shù),并且它將接收 state 作為第一個(gè)參數(shù):
export const useStore = defineStore('main', {
state: () => ({
count: 0,
}),
getters: {
doubleCount: (state) => state.count * 2,
},
})
Actions
Action 相當(dāng)于組件中的方法。
它可以通過 defineStore() 中的 actions 屬性來定義;
Action 是一種將異步操作封裝在 store 中的方式,它是一個(gè)可被調(diào)用的函數(shù),也可接收參數(shù)并修改 store 中的狀態(tài)。
import { defineStore } from 'pinia'
export const myStore = defineStore('myStore',{
state: () => ({
message: 'Hello',
}),
actions: {
async fetchMessage() {
const res = await fetch('http://127.0.0.1:5173/message')
this.message = res.message
},
},
})
4. 示例完整代碼
4.1 選項(xiàng)式寫法
// store/store.js
import { defineStore } from 'pinia';
import axios from 'axios';
export const useMainStore = defineStore('main',{
state: () => {
return {
count:0,
count2:0,
list:[],
}
},
getters:{
doubleCount(){
return this.count*2;
}
},
actions:{
add(){
this.count++;
},
update(val){
this.count = val.value;
},
add2(){
this.count2++;
},
// 異步
async getList(){
const res = await axios.get('https://api.oioweb.cn/api/common/history');
if(res.data.code == 200){
this.list = res.data.result || [];
}
},
}
})
在組件中使用
<template>
<div class="count">state:{{mainStore.count}}</div>
<div class="count">getters:{{mainStore.doubleCount}}</div>
<div class="btnWrap">
<button @click="resetStore">重 置</button>
<button @click="addCount">增 加</button>
<button @click="updateCount">更新至100</button>
</div>
<hr/>
<div class="count">state:{{count2}}</div>
<div class="btnWrap">
<button @click="add2">增 加</button>
</div>
<hr/>
<h3>歷史上的今天</h3>
<ul class="list">
<li
v-for="(item,index) in mainStore.list"
:key="index">
{{item.year}}年 - {{item.title}}
</li>
</ul>
</template>
<script setup>
import {useMainStore} from '@/store/store.js';
import {onMounted,ref} from 'vue';
import {storeToRefs} from 'pinia';
const mainStore = useMainStore();
const {count2} = storeToRefs(mainStore);
const {add2} = mainStore;
console.log(mainStore)
const number = ref(100);
const resetStore = () => {
mainStore.$reset();
}
const addCount = () => {
mainStore.add();
};
const updateCount = () => {
mainStore.update(number);
}
onMounted(() => {
mainStore.getList();
})
</script>效果:
分別觸發(fā) add2 兩次,addCount、getList 一次后的效果

4.2 組合式寫法
在組合式 API 中:
- ref() 相當(dāng)于 state 屬性;
- computed() 相當(dāng)于 getters;
- function() 相當(dāng)于 actions;
// store/count.js
import { defineStore } from 'pinia';
import {computed, ref} from 'vue';
import axios from 'axios';
// 第一個(gè)參數(shù)是應(yīng)用中 Store 的唯一 ID
export const useCountStore = defineStore('count',() => {
// state
const count = ref(0);
const count2 = ref(0);
const list = ref([]);
// getter
const doubleCount = computed(() => {
return count.value*2
})
// 同步action
const add = () => {
count.value++;
}
const update = (val) =>{
count.value = val.value;
}
const add2 = () => {
count2.value++;
}
// 異步action
const getList = async () => {
const res = await axios.get('https://api.oioweb.cn/api/common/history');
if(res.data.code == 200){
list.value = res.data.result || [];
}
}
return{
count,
count2,
doubleCount,
list,
add,
update,
add2,
getList,
}
})
在組件中使用
<template>
<div class="count">state:{{countStore.count}}</div>
<div class="count">getters:{{countStore.doubleCount}}</div>
<div class="btnWrap">
<button @click="resetStore">重 置</button>
<button @click="addCount">增 加</button>
<button @click="updateCount">更新至100</button>
</div>
<hr/>
<div class="count">state:{{count2}}</div>
<div class="btnWrap">
<button @click="add2">增 加</button>
</div>
<hr/>
<h3>歷史上的今天</h3>
<ul class="list">
<li
v-for="(item,index) in countStore.list"
:key="index">
{{item.year}}年 - {{item.title}}
</li>
</ul>
</template><script setup>
import {useCountStore} from '@/store/count.js';
import {onMounted,ref} from 'vue';
import {storeToRefs} from 'pinia';
const countStore = useCountStore();
const {count2} = storeToRefs(countStore);
const {add2} = countStore;
console.log(countStore)
const number = ref(100);
const resetStore = () => {
countStore.$reset();
}
const addCount = () => {
countStore.add();
};
const updateCount = () => {
countStore.update(number);
}
onMounted(() => {
countStore.getList();
})
</script>
效果:
分別觸發(fā) add2 兩次,addCount、getList 一次后的效果

總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- Vue3中的pinia使用方法總結(jié)(建議收藏版)
- Vue3狀態(tài)管理之Pinia的入門使用教程
- vue3項(xiàng)目使用pinia狀態(tài)管理器的使用
- vue3項(xiàng)目引入pinia報(bào)錯(cuò)的簡(jiǎn)單解決
- vue3 pinia踩坑及解決方案詳解
- Vue3中pinia的使用與持久化處理詳解
- Vue3組件不發(fā)生變化如何監(jiān)聽pinia中數(shù)據(jù)變化
- vue3中vuex與pinia的踩坑筆記記錄
- vue3搭配pinia的踩坑實(shí)戰(zhàn)記錄
- vue3?pinia實(shí)現(xiàn)持久化詳解
- vue3中使用pinia(大菠蘿)狀態(tài)管理倉(cāng)庫(kù)的項(xiàng)目實(shí)踐
- Vue3 狀態(tài)管理 Pinia 入門指南
相關(guān)文章
Vue-CLI 3.X 部署項(xiàng)目至生產(chǎn)服務(wù)器的方法
這篇文章主要介紹了Vue-CLI 3.X 部署項(xiàng)目至生產(chǎn)服務(wù)器的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03
Vue動(dòng)態(tài)創(chuàng)建注冊(cè)component的實(shí)例代碼
這篇文章主要給大家介紹了關(guān)于Vue動(dòng)態(tài)創(chuàng)建注冊(cè)component的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Vue具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06
解決echarts echarts數(shù)據(jù)動(dòng)態(tài)更新和dataZoom被重置問題
這篇文章主要介紹了解決echarts echarts數(shù)據(jù)動(dòng)態(tài)更新和dataZoom被重置問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-07-07
一款移動(dòng)優(yōu)先的Solid.js路由solid router stack使用詳解
這篇文章主要為大家介紹了一款移動(dòng)優(yōu)先的Solid.js路由solid router stack使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
Element-ui樹形控件el-tree自定義增刪改和局部刷新及懶加載操作
這篇文章主要介紹了Element-ui樹形控件el-tree自定義增刪改和局部刷新及懶加載操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-08-08
關(guān)于vue中如何監(jiān)聽數(shù)組變化
這篇文章主要介紹了關(guān)于vue中如何監(jiān)聽數(shù)組變化,對(duì)vue感興趣的同學(xué),必須得參考下2021-04-04
Vue ElementUI實(shí)現(xiàn):限制輸入框只能輸入正整數(shù)的問題
這篇文章主要介紹了Vue ElementUI實(shí)現(xiàn):限制輸入框只能輸入正整數(shù)的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-07-07
windows下vue-cli導(dǎo)入bootstrap樣式
這篇文章主要介紹了windows下vue-cli導(dǎo)入bootstrap樣式,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-04-04

