23年用vuex進行狀態管理out了,都開始用pinia啦!
1 Vue2項目中,Vuex狀態管理工具,幾乎可以說是必不可少的了。而在Vu3中,尤大大推薦我們使用pinia(拍你啊)進行狀態管理,咱得聽話,用就完了。
使用之前我們來看一下,使用 pinia 給我們帶來哪些好處?
官網介紹:Pinia 是 Vue 的存儲庫,它允許您跨組件/頁面共享狀態
個人理解:在我看來就是變態版 vuex,聽說是為了尊重原作者,所以給改名了叫 pinia(拍你啊)
看看都有啥變態的
- 兼容 vue2、vue3,該說不說這一點 vuex 也支持
- Typescript 支持更友好
- 體積小,1kb 左右,vuex 350k 以上
- 支持插件擴展和服務器端渲染 ssr
- pinia 只有 state、getter、action,拋棄了 Vuex 中的 Mutation。
- mutation 干啥了?vuex 中改/處理變數據源 store 數據的集合(唯一的),必須是同步。
- 我們需要在組件里面調用 dispatch() 方法提交 Actions
- Actions 再通過 commit 方法提交 mutations
- 通過 mutations 里面的方法修改 state(數據)
- 最后 render 到組件里面
- 為啥同步?
- mutation 中如果寫異步 Le,commit 在觸發 mutation 事件時,異步的回調函數不知道是什么時候執行的,所以在 devtools 中難以追蹤變化了
- mutation 干啥了?vuex 中改/處理變數據源 store 數據的集合(唯一的),必須是同步。
- pinia 中 action 支持同步和異步。上面也說了下為啥,還不知道為啥可以搜一下為啥。
- 不用創建各個模塊嵌套了。Vuex 中才分不同模塊我們需要用到 modules:模塊化拆分。在 pinia 中每個 store 都是獨立的,互相不影響,沒啥事。
用 vue3 demo 講解 pinia 的使用。
1、搭建項目、安裝以來
Vue3 + TS + Vite 項目
參考:Vue3.x 全家桶+vite+TS-搭建 Vue3.x 項目
參考:vue3 學習
1). 創建項目
npm create vite@latest my-vite-app --template vue-ts
2). 安裝 pinia 依賴
npm install pinia
3).全局掛在 pinia
我們在 main.ts 主文件中,引入 pinia 的createPinia 方法, 創建根存儲,以方便全局調用。
import { createApp } from "vue";
import App from "./App.vue";
import { createPinia } from "pinia";
const pinia = createPinia();
const app = createApp(App);
app.use(pinia);
app.mount("#app");
2、搞正事,創建數據倉庫 store
應用場景:
. 多個視圖依賴于同一狀態。
. 來自不同視圖的行為需要變更同一狀態。
我們需要用到 pinia 的defineStore() 方法,創建一個 store。
defineStore:
- 參數 1:(name) store 的唯一標識 id。也就是 vuex 中 modules:模塊化拆分的模塊標識
- 參數 2:(options) 相關配置,通俗來講就是數據,和修改數據的一系列方法 state、getter、action 都在這里
創建后編寫代碼如下:
/src/store/piniaStore.ts
import { defineStore } from 'pinia'
export const useUsersStore = defineStore('pinia_id', {
})
3、組件中調用 pinia
我們在上一步已經引入了 pinia,并且在 store 文件下創建了一個叫 piniaStore 的 store,接下來讓我們看看在組件里如何調用
<script setup lang="ts">
import { useUsersStore } from "../src/store/piniaStore";
const store = useUsersStore();
console.log(store);
</script>
方法很簡單一個 useUsersStore 方法搞定,我們看一下打印內容:
$dispose: f $dispose()$id: "pinia_id"
$onAction: f ()
$patch: f $patch(partialStateOrMutator)
$reset: f Sreset()
$subscribe: Ssubscribe(callback, options2 = ) const removeSubscription = addSuoscription(suhotUpdate: (newStore) => f...]
也就這些哈,沒啥玩楞。
4、state 屬性
我們往 store 里加點數據源 state 吧!
export const useUsersStore = defineStore("pinia_id", {
state: () => {
return {
age: 20,
message:'我來存放公共數據哈!'
sex: "男",
};
},
});
4.1 讀取 state 數據
回想一下 vuex 怎么訪問的
- 組件中訪問 State 中數據的第一種方式:
this.$store.state.全局數據名稱
- 組件中訪問 State 中數據的第二種方式:
// 從vuex中按需導入mapState函數
import { mapState } from 'vuex'
// 將全局數據 因設為當前組件的計算屬性
computed: {
...mapState(['count'])
}
pinia 如何訪問呢?
其實我們定義的 state 數據就在 useUsersStore 內,我們自行就可以直接拿到相關數據
<template>
<p>描述:{{ message }}</p>
<p>年齡:{{ age }}</p>
<p>性別:{{ sex }}</p>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { useUsersStore } from "../src/store/piniaStore";
const store = useUsersStore();
const message = ref<string>(store.message);
const age = ref<number>(store.age);
const sex = ref<string>(store.sex);
</script>
當然我們也可以用 es6 解構賦值來優化一下
const { message, age, sex } = store;
4.2 多個組件使用 state
我們使用 pinia 更想做到多組件公用統一數據,新建一個 Child.vue 其實用法很簡單直接調用使用即可
<template>
<p>我是一個子元素</p>
<p>描述:{{ message }}</p>
<p>年齡:{{ age }}</p>
<p>性別:{{ sex }}</p>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { useUsersStore } from "../src/store/piniaStore";
const store = useUsersStore();
const { message, age, sex } = store;
</script>
4.3 修改 state 數據
我們在回想一下 vuex 怎么修改的
- 有人很暴力:直接 this.$store.state.全局數據名稱 直接去修改,這種方式很難查看數據是被什么組件修改
- mutation 修改
① 只能通過 mutation 變更 store 數據,不可以直接操作 store 中的數據
② 通過這種方式雖然操作起來繁瑣,但是可以集中監控所有數據的變化
看看 pinia
其實如果想要修改修改 store 中的數據,可以直接重新賦值
<template>
<img alt="Vue logo" src="./assets/logo.png" />
<p>年齡:{{ age }}</p>
<button @click="changeAge">年齡不對</button>
</template>
<script setup lang="ts">
import child from './child.vue';
import { useUsersStore } from "../src/store/piniaStore";
const store = useUsersStore();
const { nage,} = store;
const changeAge = () => {
store.age = 26;
console.log(store);
};
</script>
打印可也看出。store 中 age 數據發生了改變,再看看,呦呵,頁面沒響應。
我們可能去監聽 store 數據變化然后刷新頁面,但有個更好的方法等著我們
pinia 的storeToRefs 方法把我們的 state 變得具有響應
import { storeToRefs } from 'pinia';
const store = useUsersStore();
const { message, age, sex } = storeToRefs(store);
4.4 初始化/重置 state 數據
store 的$reset()方法為我們提供了 state 數據重置的可能
<button @click="onResetData">重置store</button>
const onResetData = () => {
store.$reset();
};
4.5 store 的$patch 方法批量修改數據
- 全部調整:此方法需要一次性將 state 中的所有字段例舉出。
store.$patch({
message: "批量搞事情",
age: 100,
sex: "女",
});
- 部分修改: $patch 方法接收一個回調函數,用來修改部分數據
store.$patch((state) => {
state.items.push({ message: 'shoes', quantity: 1 })
state.hasChanged = true
})
4.6 直接替換 state
store.$state = { counter: 666, name: 'yup' }
5、getter 屬性
Getter 用于對 Store 中的數據進行加工處理形成新的數據
- Getter 可以對 Store 中已有的數據加工處理之后形成新的數據,類似 Vue 的計算屬性,不會影響到原本的數據
- Store 中的數據發生變化,Getter 的數據也會跟著變化
5.1 添加 getter
export const useUsersStore = defineStore("pinia_id", {
state: () => {
return {
age: 25,
sex: "男",
};
},
getters: {
getAddAge: (state) => {
return state.age + 100;
},
},
});
5.2 調用 getter
- 直接在標簽上使用 getter 定義的方法,這種方式是響應式的,可以直接監聽到變化,其實 state 標簽直接調用也是一樣相應的
<template>
<p>新年齡:{{ store.getAddAge }}</p>
<button @click="patchStore">批量修改數據</button>
</template>
<script setup lang="ts">
import { useUsersStore } from "../src/store/piniaStore";
const store = useUsersStore();
// 批量修改數據
const patchStore = () => {
store.$patch({
age: 100,
sex: "女",
});
};
</script>
- getter 中調用其它 getter
這里需要注意一下,不要箭頭函數
export const useUsersStore = defineStore("users", {
state: () => {
return {
age: 25,
sex: "男",
};
},
getters: {
getAddAge: (state) => {
return state.age + 100;
},
getNameAndAge(): string {
return this.name + this.getAddAge; // 調用其它getter
},
},
});
5.3 getter 傳參
上文提到 getter 與計算屬性差不多,想想計算屬性怎么傳遞的呢?
computed:{
getNewName(){
function (str){
return str+this.name
}
}
}
看一下 getter 的
<p>新年齡:{{ store.getAddAge(1100) }}</p>
getters: {
getAddAge: (state) => {
return (num: number) => state.age + num;
},
getNameAndAge(): string {
return this.name + this.getAddAge; // 調用其它getter
},
},
6. actions 屬性
對數據進行邏輯加工,完成默寫特定的業務邏輯。和 vue 組件代碼中的 methods 相似,存放一些處理業務邏輯的方法。
6.1 添加 actions
export const useUsersStore = defineStore("pinia_id", {
state: () => {
return {
message: "",
age: 25,
sex: "男",
name:'王'
};
},
getters: {
getAddAge: (state) => {
return (num: number) => state.age + num;
},
getNameAndAge(): string {
return this.name + this.getAddAge; // 調用其它getter
},
},
actions: {
saveName(name: string) {
this.name = name;
},
},
});
6.2 使用 actions
const saveName = () => {
store.saveName("我用來調用action內的方法");
};
至此文章結束!

浙公網安備 33010602011771號