在學習 Pinia 之後,我便決心為我的舊專案導入狀態管理
於是我挑了我之前做的虛構電商網站來導入 Pinia
在使用 Vue.js 開發 SPA 的時候,我們會將每一頁乃至於頁面中的其中一部份切分成單一的元件
而元件本身的資料是獨立的
簡單來說,a.vue 中可以有 cart, b.vue 中也可以有同名的 cart,兩者互不衝突
然而,這樣的情況下也會遇到困難
也就是跨元件的資料傳遞
在我的專案中,有一個 UserNavbar.vue 元件
它會顯示現在購物車裡面有多少筆商品
然而,我們卻會在其他元件中觸發加入購物車的方法
這時候購物車內商品的數量發生改變,我們就必須讓 UserNavbar.vue 正確抓到更新後的數量
然而,觸發的元件與 UserNavbar.vue 之間要跨多層元件傳送,無法輕易的使用 props 解決問題
簡單來說,我有了跨元件的資料傳遞
的需求
之前我使用的是 mitt
首先我們單獨建立一個 emitter.js
import mitt from 'mitt'
const emitter = mitt()
export default emitter
然後在 UserNavbar.vue 中 import
import emitter from '@/methods/emitter'
......
mounted () {
emitter.on('update-cart', () => {
this.getCart() //更新購物車數量
})
}
我們透過 mitt 註冊了一個 update-cart 事件,這樣不管在哪一個元件中,我們都可以透過觸發這個事件來讓購物車更新
// UserProduct.vue
import emitter from '@/methods/emitter'
......
addCart (id) {
......
this.$http.post(api, { data: { product_id: id, qty: 1 } }).then(() => {
emitter.emit('update-cart') // 觸發 UserNavbar.vue 中註冊的事件
})
},
mitt 這樣的作法,只是幫我們便於掛元件傳遞,並沒有資料狀態的管理效果
data 仍是四散於各個元件內
pinia 就是真正的狀態管理工具了
比起 mitt,pinia 不單單可以做到跨元件的資料傳遞,更能夠實踐統一管理
簡單來說,我們原先購物車的內容是四散於每一個元件中的data內
每個元件中的購物車資料都是獨立的
而 pinia 將其集中的一隻獨立的 store 檔案中進行單獨管理
cartStore.js 中會包含了購物車的資料狀態(state),改變購物車的方法(actions),取得購物車資料的處理(getters)等等
import { defineStore } from 'pinia'
export default defineStore('cartStore', {
state: () => ({
cart: {
carts: []
}
}),
actions: {
getCart () {
......
},
addCart (id, qty = 1) {
......
}
}
})
透過 pinia ,我們會建立一個 store 將資料狀態和方法存在 store 中,並透過 store 中的方法更新資料,最後再把資料傳遞到所需要的元件內
改用了 pinia 之後,我更新 UserNavbar.vue 的流程變成這樣
// UserProduct.vue
<button class="..." type="button" @click="addCart(product.id, qty)"></button>
import cartStore from '@/stores/cartStore'
import { mapActions } from 'pinia'
......
methods: {
......
...mapActions(cartStore, ['addCart'])
}
我們直接從 cartStore.js 中匯入更新購物車的方法,然後通過模板中的按鈕觸發 cartStore.js 中的 actions
這樣我們無論是購物車的資料,還是更新購物車的方法,都是透過 cartStore.js 統一進行管理的
而當 cartStore.js 中的購物車資料改變的時候
因為 UserNavbar.vue 也是獲取同一個 cartStore.js 中的購物車資料,我們也就不用額外去觸發什麼來更新 UserNavbar.vue 了
<div class="...">{{ cart.length }}</div>
import cartStore from '@/stores/cartStore'
......
computed: {
...mapState(cartStore, ['cart'])
}
透過 pinia
當我們在元件 A 中修改了 store 中的資料,其他匯入了相同 store 的元件,資料也會同時改變
這就不僅僅實現了跨元件的資料傳遞,更實現了狀態管理