Vuex存储JavaScript类实例后自动转为普通对象的问题
解决Vuex存储类实例变为普通对象的问题
这个坑我之前踩过!你遇到的问题本质是Vue的响应式系统会自动把存入Vuex state的类实例转换成普通响应式对象,导致类的原型链、getter/setter以及方法全部丢失。
为什么mutation里的两次console.log都显示正常?因为刚把实例push进数组时,Vue还没来得及对这个新对象做响应式处理,等你后续通过getter访问时,Vue已经完成了响应式转换,把实例变成了普通对象。
下面给你两种实用的解决方案,根据你的需求选:
方案一:在Getter中重构类实例(推荐,支持响应式)
如果需要Coin实例的属性变化能触发视图更新,那就把state里存储的普通对象在getter中重新构造成Coin实例:
修改你的Vuex模块的getters:
const getters = { ownedCoins (state) { // 把每个普通对象重新转为Coin实例 return state.ownedCoins.map(coinObj => { return new Coin(coinObj._name, coinObj._amount, coinObj._priceBought) }) }, }
这样每次通过this.$store.getters.ownedCoins获取的都是完整的Coin实例,而且state里的普通对象是响应式的,属性变化会自动触发getter重新计算,视图也会更新。
方案二:标记实例为非响应式(适合不需要响应式的场景)
如果你的Coin实例不需要响应式(比如属性不会动态变化,或者不需要视图跟着更新),可以用Vue的markRaw方法把实例标记为“不需要被响应式处理”,这样Vuex就会保留原始的类实例:
Vue 3写法:
import { markRaw } from 'vue' // 创建实例时标记为非响应式 const coin = markRaw(new Coin( this.formAdd.coin, this.formAdd.amount, this.formAdd.price )) this.$store.commit('ADD_COIN', coin)
Vue 2写法:
// Vue2里用Vue.util.markRaw const coin = Vue.util.markRaw(new Coin( this.formAdd.coin, this.formAdd.amount, this.formAdd.price )) this.$store.commit('ADD_COIN', coin)
这个方法的好处是直接保留原始实例,但代价是实例的属性变化不会触发视图更新,按需选择就好。
补充说明
你可以测试一下:在mutation的ADD_COIN里加一个setTimeout,延迟一点再打印state.ownedCoins,就会发现实例已经变成普通对象了——这就是Vue的响应式系统在后台处理的结果。
内容的提问来源于stack exchange,提问作者Pascal
相关产品推荐
相关产品推荐

