在学习 Pinia 之后,我便决心为我的旧专案导入状态管理于是我挑了我之前做的虚构电商网站来导入 Pinia
为什么要使用 Pinia
在使用 Vue.js 开发 SPA 的时候,我们会将每一页乃至于页面中的其中一部份切分成单一的元件而元件本身的资料是独立的简单来说,a.vue 中可以有 cart, b.vue 中也可以有同名的 cart,两者互不冲突然而,这样的情况下也会遇到困难也就是跨元件的资料传递
在我的专案中,有一个 UserNavbar.vue 元件它会显示现在购物车里面有多少笔商品然而,我们却会在其他元件中触发加入购物车的方法这时候购物车内商品的数量发生改变,我们就必须让 UserNavbar.vue 正确抓到更新后的数量然而,触发的元件与 UserNavbar.vue 之间要跨多层元件传送,无法轻易的使用 props 解决问题简单来说,我有了跨元件的资料传递的需求
mitt
之前我使用的是 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
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 的元件,资料也会同时改变这就不仅仅实现了跨元件的资料传递,更实现了状态管理