TypeScript?Pinia實戰(zhàn)分享(Vuex和Pinia對比梳理總結(jié))
簡介
今天我們再來實戰(zhàn)下官方推薦的新的vue狀態(tài)管理工具Pinia。
pinia 由 vue 團隊中成員所開發(fā)的,因此也被認(rèn)為是下一代的 vuex,即 vuex5.x,在 vue3 的項目中使用也是備受推崇。所以 pinia 的學(xué)習(xí)迫在眉睫。
下面我們正式開始pinia的學(xué)習(xí)吧。
安裝
yarn add pinia // or npm install pinia
創(chuàng)建pinia并傳遞給vue實例
創(chuàng)建一個 pinia 并傳遞給 vue 應(yīng)用。
在這一步我們可以發(fā)現(xiàn),我們只需要簡單創(chuàng)建一個pinia對象傳給vue實例就可以自動收集我們后續(xù)創(chuàng)建的新store。并不需要像vuex一樣把各個模塊聚集在根store里面?zhèn)鬟f給vue實例。總體來說使用更加簡單。
import { createPinia } from 'pinia'
import { createApp } from 'vue'
import App from './app.vue'
createApp(App).use(createPinia()).mount('#app')創(chuàng)建store
與vuex不同,pinia沒有了根store和modules的概念。在pinia中一個store一個文件,一個store里面包含state、getters、actions三部分??傮w來說更簡單更清晰。
需要使用defineStore來創(chuàng)建store。
注意第一個參數(shù)一定要唯一
import { defineStore } from "pinia";
export const mainStore = defineStore("main", {
state: () => {
return {
name: "randy man",
age: 24,
};
},
getters: {
getterName(state) {
return state.name.toUpperCase() + "-----" + state.age;
},
// 這種方式也可以,不過需要自己手動指定返回值類型
getterAge(): number {
return this.age;
},
},
actions: {
// 直接使用this修改state
changeName(payload: string) {
this.name = payload;
return "success";
},
// 異步action
async fetchData(payload: number) {
const response = await fetch(
`https://jsonplaceholder.typicode.com/todos/${payload}`
);
const res = response.json();
// 調(diào)用其他action
// this.changeName("xxx");
return res;
},
},
});下面我們詳細(xì)介紹下第二個參數(shù)。
state
state就是狀態(tài),和vuex一樣,就不過多介紹了。只需要注意他是一個方法,返回一個state對象。
state: () => {
return {
name: "randy man",
age: 24,
};
},
getters
getters是計算屬性,和vuex中是一樣的。但是需要知道它支持兩種寫法。
通過this修改state的方式需要自己手動指定返回值類型。
getters: {
getterName(state) {
return state.name.toUpperCase() + "-----" + state.age;
},
// 這種方式也可以,不過需要自己手動指定返回值類型
getterAge(): number {
return this.age;
},
},actions
在pinia中沒有了mutations,所以同步和異步操作都在action中進行。
并且在pinia中是支持直接調(diào)用別的action,或者別的模塊的action。
actions: {
// 直接使用this修改state
changeName(payload: string) {
this.name = payload;
return "success";
},
// 異步action
async fetchData(payload: number) {
const response = await fetch(
`https://jsonplaceholder.typicode.com/todos/${payload}`
);
const res = response.json();
// 調(diào)用其他action
// this.changeName("xxx");
return res;
},
},在 action 里調(diào)用其他 store 里的 action 也比較簡單,引入對應(yīng)的 store 后即可訪問其內(nèi)部的方法了,跟在vue組件中使用是一樣的。
// user.ts
import { useAppStore } from './app'
export const useUserStore = defineStore({
id: 'user',
actions: {
async login(account, pwd) {
const { data } = await api.login(account, pwd)
const appStore = useAppStore()
appStore.setData(data) // 調(diào)用 app store 里的 action 方法
return data
}
}
})在vue組件使用
在vue組件中使用也很簡單,需要使用哪個store引入哪個store就可以啦。
<template>
<div>
<div>name: {{ name }}</div>
<div>getterName: {{ getterName }}</div>
<div>
<button @click="updateMainName">修改main name</button>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, computed } from "vue";
import { mainStore } from "@/pinia/main";
import { storeToRefs } from "pinia";
export default defineComponent({
name: "PiniaView",
setup() {
const store = mainStore();
const updateMainName = async () => {
// 直接修改 不建議
// store.name = "demi woman";
// 對象形式修改
// store.$patch({ name: "demi woman" });
// 函數(shù)形式修改
// store.$patch((state) => {
// state.name = "demi woman";
// });
// 通過action修改
const result = store.changeName("demi woman");
console.log(result);
// 返回的值不會被Promise包裹
const result2 = await store.fetchData(1);
console.log(result2);
};
// 直接解構(gòu)不能響應(yīng)式
// const { name, getterName } = store;
// 這樣響應(yīng)式
const name = computed(() => store.name);
const getterName = computed(() => store.getterName);
// 這樣也能響應(yīng)式
// const { name, getterName } = storeToRefs(store);
return {
name,
getterName,
updateMainName,
};
},
});
</script>跟vuex相比,使用pinia不需要定義state類型,不用定義key就能得到TypeScript的優(yōu)勢。

可以看到我們使用store的時候,它的所有屬性和方法state、getters、actions等都會自動提示出來,并且當(dāng)我們使用了不存在的屬性在編碼期間會直接報錯。

獲取state
獲取state的方式有三種,但是需要注意通過直接解構(gòu)的方式數(shù)據(jù)是不會響應(yīng)式的。如果需要響應(yīng)式需要使用computed或storeToRefs
import { storeToRefs } from "pinia";
const store = mainStore();
// 直接解構(gòu)不能響應(yīng)式
// const { name } = store;
// 這樣響應(yīng)式
const name = computed(() => store.name);
// 這樣也能響應(yīng)式
// const { name } = storeToRefs(store);獲取getters
獲取getters的方式也有三種,但是需要注意通過直接解構(gòu)的方式數(shù)據(jù)是不會響應(yīng)式的。如果需要響應(yīng)式需要使用computed或storeToRefs
import { storeToRefs } from "pinia";
const store = mainStore();
// 直接解構(gòu)不能響應(yīng)式
// const { getterName } = store;
// 這樣響應(yīng)式
const getterName = computed(() => store.getterName);
// 這樣也能響應(yīng)式
// const { getterName } = storeToRefs(store);
修改state
修改state的方式也有很多種,可以直接修改、還可以使用$patch來傳遞對象或方法來修改、還可以通過action修改。
const updateMainName = async () => {
// 直接修改 不建議
// store.name = "demi woman";
// 對象形式修改
// store.$patch({ name: "demi woman" });
// 函數(shù)形式修改
// store.$patch((state) => {
// state.name = "demi woman";
// });
// 通過action修改
const result = store.changeName("demi woman");
// action 返回啥就是啥 result等于'success'
};
雖然修改方式很多,但是還是在實際開發(fā)中推薦使用action來修改state。
使用action的時候還有一點需要注意。我們知道在vuex中,action如果有返回值是會被Promise包裹resolve出來,也就是會返回一個Promise對象。但是在pinia中,action返回啥就是啥不會被Promise包裹resolve出來。
數(shù)據(jù)持久化
我們知道,vuex和pinia本質(zhì)上都是對象,都是臨時存儲,當(dāng)頁面刷新數(shù)據(jù)都會丟失。
想要刷新不丟失就需要我們手動存儲在localStorage或sessionStorage里面。如果不想手動處理,我們也可以使用插件。
vuex使用vuex-persistedstate
pinia使用pinia-plugin-persistedstate
具體怎么使用筆者就不再贅述了大家可以自行查看文檔,原理都是一樣的,通過配置將指定數(shù)據(jù)存儲到localStorage或sessionStorage里面實現(xiàn)數(shù)據(jù)持久化。
總結(jié)
pinia有完整的typescript的支持。不再像使用vuex需要定義key、定義state類型那么麻煩。- 足夠輕量,壓縮后的體積只有
1.6kb。 - 去除
mutations,只有state,getters,actions。跟react-redux類似,同步異步都在action里面進行。根簡單清晰。 - 沒有模塊嵌套,只有
store的概念,store之間可以自由使用,更好的代碼分割。更簡單易懂。 - 無需手動添加
store,store一旦創(chuàng)建便會自動添加,我們只需要在vue組件直接引用需要的store使用即可。
到此這篇關(guān)于TypeScript Pinia實戰(zhàn)分享(Vuex和Pinia對比梳理總結(jié))的文章就介紹到這了,更多相關(guān)TypeScript Pinia 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
el-date-picker與el-time-picker的時間格式設(shè)置代碼
這篇文章主要介紹了el-date-picker與el-time-picker的時間格式設(shè)置代碼,代碼簡單易懂,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2023-11-11
讓innerText在firefox火狐和IE瀏覽器都能用的寫法
下面的代碼主要是用來解決firefox瀏覽器不支持innerText的問題,需要的朋友可以參考下。2011-05-05
TypeScript中Map對象使用及Map與字典的區(qū)別詳解
Map對象主要的應(yīng)用場景在于數(shù)據(jù)重組和數(shù)據(jù)儲存,下面這篇文章主要給大家介紹了TypeScript中Map對象使用及Map與字典的區(qū)別的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-01-01
深入理解JavaScript系列(35):設(shè)計模式之迭代器模式詳解
這篇文章主要介紹了深入理解JavaScript系列(35):設(shè)計模式之迭代器模式詳解,迭代器模式(Iterator):提供一種方法順序一個聚合對象中各個元素,而又不暴露該對象內(nèi)部表示,需要的朋友可以參考下2015-03-03

