pinia
主要包括以下五部分,經常用到的是 store、state、getters、actions
以下使用說明,注意事項,僅限于 vue3 setup
語法糖中使用,若使用選項式 API
請直接查看官方文檔:
一、前言:
pinia
是為了探索 vuex
下一次迭代是要實現那些功能用途,pinia
已實現vuex5
的絕大部分功能;
并且與 Vuex
相比,Pinia
提供了一個更簡單的 API
,具有更少的規范,提供了 Composition-API 風格的 API
,最重要的是,在與 TypeScript
一起使用時具有可靠的類型推斷支持;
二、pinia 與vuex <= 4.x 的差異
1、****mutations
不再存在。他們經常被認為是 非常 冗長。他們最初帶來了 devtools
集成,但這不再是問題。
**2、**無需創建自定義復雜包裝器來支持 TypeScript
,所有內容都是類型化的,并且 API
的設計方式盡可能利用 TS
類型推斷。
**3、**不再需要注入、導入函數、調用函數、享受自動完成功能
!
4、****無需動態添加 Store
,默認情況下它們都是動態的,您甚至都不會注意到。請注意,您仍然可以隨時手動使用 Store 進行注冊,但因為它是自動的,您無需擔心。
**5、**不再有 modules
的嵌套結構。您仍然可以通過在另一個 Store 中導入和 使用
來隱式嵌套 Store
,但 Pinia
通過設計提供平面結構
,同時仍然支持 Store 之間的交叉組合方式
。 您甚至可以擁有 Store 的循環依賴關系。
**6、**沒有 命名空間模塊。鑒于 Store
的扁平架構,“命名空間” Store
是其定義方式所固有的,您可以說所有 Store
都是命名空間的。
三、store:
store:它持有未綁定到您的組件樹的狀態和業務邏輯
;托管全局狀態
像一個始終存在并且每個人都可以讀取和寫入的組件;
主要有三個方法:state、getters、actions
,類似于組件中數據、計算屬性、方法;
用于存儲不同組件直接共享的數據實例方法,以及頁面之間需要保留的數據狀態;
// count.ts 文件
<script lang="ts">
import { defineStore } from 'pinia'
// defineStore 的第一個參數是 唯一標識ID 用于關聯 devtool 調試使用
// 第二個參數是 一個對象 包含 state、actions,gettes
// 聲明的 屬性useCount 建議以 use 開頭,保持書寫的統一性
export const useCount = defineStore('count', {state:() => {return{}},actions: {},gettes: {}
})
</script>
在組件中使用:
注意:若 解構使用 store 中的屬性 方法,需要使用 storeToRefs()
或者 toRefs()
讓其保持響應式
<script setup>import { toRefs } from 'vue'import { storeToRefs } from 'pinia'import { useCount } from '@/store'const count = useCount()// 這樣解構獲取 store 中屬性方法,會丟失響應式const { num } = count// 1、使用 pinia自帶的storeToRefs(), 將store中屬性轉換為 ref 數據以保持響應式const { doubleCountAdd } = storeToRefs(count)console.log('=doubleCountAdd==', doubleCountAdd)// 2、使用vue3 的 toRefs() 轉化為 ref 響應式數據const { doubleCount } = toRefs(count)console.log('=doubleCount==', doubleCount)
</script>
四、state:
state: 類似組件中的 data(){return{}}
,但是在 pinia 中的state 建議書寫為:
使用箭頭函數,用于完整推斷類型
state: () => {return {name: 'Andy',num: 0}
}
組件中使用:
<script setup lang='ts'>import { useCount } from '@/store'const count = useCount()// 1、直接調用或者修改console.log(count.name)// 2、通過$patch({}) 同時修改多個屬性count.$patch({name: '刺客',num++})// 或者傳入一個回調函數count.$patch((state) => {state.count = '4'})
</script>
五、actions:
actions 類似組件中的methods
,可以在組件中直接調用里面的方法
// count.ts 文件
<script lang="ts">
export const useCount = defineStore('count', {state: () => {return{name: 'Andy',num: 0}},actions: {add() {// 直接通過 this 調用 state 中的屬性,也可以調用其他 store 中屬性,只需引入即可this.num++},},
})
</script>
組件中可以直接通過 調用 add()
方法來修改 num
<script setup>import { useCount } from '@/store'const count = useCount()count.add()
</script>
六、gettes:
相當于組件中的 computed
計算屬性:
// count.ts 文件
<script lang='ts'>
import { defineStore } from 'pinia'
export const useCount = defineStore('count', {state: () => {return{name: 'Andy',num: 0}},getters: {// 相當于組件中的 計算屬性doubleCount(state): number {return state.num * 2},doubleCountAdd():number {// 可以在其他 getter 中直接調用另一個getterreturn this.doubleCount + 1},// 接收額外參數時,需要返回一個函數處理doubleCountAdd2:(state) => {return (num:number):number => state.num * num} }
})
</script>
在組件中可以直接使用
<script setup>
import { useCount } from '@/store'
const count = useCount()
console.log(count.doubleCountAdd)
count.$patch({name: '刺客',num: 3
})const doubleCountAdd2 = count.doubleCountAdd2(8)// 上面state.num 值為 3, 傳入 額外參數 為8,故最后為 3* 8 = 24
</script>
完整代碼如下:
// count.ts 文件
import { defineStore } from 'pinia'
// 通過 defineStore 定義的 store 第一個參數 count 是唯一的id,用于鏈接devtool
// 定義 一個id 為count的 store export const useCount = defineStore('count', {state: () => {return{name: 'Andy',num: 0}},actions: {add() {this.num++},},// getter 只會依賴狀態getters: {// 相當于組件中的 計算屬性doubleCount(state): number {return state.num * 2},doubleCountAdd():number {// 可以在其他 getter 中直接調用另一個getterreturn this.doubleCount + 1},// 接收額外參數,返回一個函數處理doubleCountAdd2:(state) => {return (num:number):number => state.num * num} },// 若不需要額外配置,// persist: true,// 額外配置persist: {// key: 'piniaStore', //存儲名稱// storage: sessionStorage, // 存儲方式 默認存儲在localStorage// paths: ['name'], //指定 state 中哪些數據需要被持久化。[] 表示不持久化任何狀態,undefined 或 null 表示持久化整個 state}
})
// main.ts 文件
import { createApp } from 'vue'
import { createPinia } from 'pinia'
const app = createApp(App)
const pinia = createPinia()
//導入pinia 持久化 插件
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
pinia.use(piniaPluginPersistedstate)
app.use(pinia)
app.mount('#app')
// 單文件組件 myPinia/index.vue 文件中使用
<template><div class="myPinia">This is a text demo of the pinia.<hr><div>count.num: {{ count.num }}</div><div>count.doubleCount: {{ count.doubleCount }}</div><div>count.doubleCountAdd: {{ count.doubleCountAdd }}</div><div>num: {{ num }}</div><div>doubleCountAdd: {{ doubleCountAdd }}</div><div>doubleCount: {{ doubleCount }}</div><div>doubleCountAdd2: <span>{{ doubleCountAdd2 }}</span></div><button @click="count.add()">add</button></div>
</template><script setup>
import { toRefs } from 'vue'
import { storeToRefs } from 'pinia'
import { useCount } from '@/store'
const count = useCount()
console.log('==count==', count)
// 解構獲取 store 中屬性方法,不是響應式
const { num } = count
// 1、使用 pinia自帶的storeToRefs(), 將store中屬性轉換為 ref 數據以保持響應式
const { doubleCountAdd } = storeToRefs(count)
console.log('=doubleCountAdd==', doubleCountAdd)
// 2、使用vue3 的 toRefs() 轉化為 ref 響應式數據
const { doubleCount } = toRefs(count)
console.log('=doubleCount==', doubleCount)
// 通過 $patch 修改state 中多個屬性
count.$patch({name: '刺客',num: 3})// 傳入額外參數const doubleCountAdd2 = count.doubleCountAdd2(8) // 上面state.num 值為 3, 傳入 額外參數 為8,故最后為 3* 8 = 24
</script><style lang="scss" scoped>div{font-size: 18px;color: #333;span {color: red;}
}
</style>