Vue3 Options API中Store设相同对象仍触发watch的原因咨询
问题:Vue3 Options API中watch监听数组,每次调用push都会触发(即使添加相同对象)
我用Vue3的Options API开发,每次调用StoreTest.setters.set()往store的数组里加完全相同的对象时,对应的watch监听都会触发。按我理解,这个watch应该只在数组被设置为不同值时才触发,想知道为啥会这样?
调用set的代码
StoreTest.setters.set({ geojson: this.#featureRecentlyRequestedProcessing.value.get(DigitizePolygonConstants.CONST_DIGITIZED_FEATURE_PROPERTY_GEOJSON.description), order: this.#featureRecentlyRequestedProcessing.value.get(DigitizePolygonConstants.CONST_DIGITIZED_FEATURE_PROPERTY_GEOM_ORDER.description), });
storeTest.vue代码
<script> import { reactive } from 'vue'; export default { } export const StoreTest = ({ state: reactive({ array: [], }), getters: { get() { return StoreTest.state.array; }, }, setters: { set(obj) { StoreTest.state.array.push(obj); }, }, actions: { initialize() { StoreTest.state.array = []; }, } }); </script>
watch监听代码
created() { console.log(verboseTag, 'created()'); this.$watch(this.refStoreTest.getters.get, (newVal, oldVal) => { msg = JSON.stringify({msg: verboseTag + '@watch refStoreTest.getters.get()', newVal: newVal, oldVal: oldVal}); console.log(msg); newVal = newVal.sort((a,b) => a.order-b.order); this.refStroeRecentlyHoveredGeometriesProps.setters.set(newVal); }, { deep: true }); }
原因分析
deep: true的深度监听逻辑:你给watch开了深度监听,Vue会递归检查数组的内部变化。哪怕数组引用没变,只要调用push修改了数组的长度、内部元素位置,深度监听都会捕捉到这个变更,触发回调。- 数组变异方法的响应式拦截:Vue对数组的
push/pop/sort等变异方法做了特殊拦截,只要调用这些方法修改数组,不管添加的元素是不是重复对象,都会触发依赖更新,而你的watch会响应这个更新。 - 对象相同不等于引用相同:就算你添加的对象内容完全一致,每次调用
set时都是生成了新的对象引用;哪怕复用同一个对象引用,push操作依然会改变数组长度,深度监听照样会触发。
解决办法
如果只想在数组内容真正发生变化(而非单纯调用变异方法或添加重复对象)时触发watch,可以试试这些方案:
- 监听数组的序列化值,关闭深度监听:把数组转成JSON字符串监听,只有内容真正变化时才会触发回调(注意:仅适用于元素可序列化的场景,函数、Symbol等不可序列化值会丢失):
this.$watch( () => JSON.stringify(this.refStoreTest.getters.get()), (newVal, oldVal) => { // 你的回调逻辑 } );
- 在setter里先做重复判断:在
StoreTest.setters.set方法中,先检查要添加的对象是否已存在,只有不存在时才执行push,从根源避免重复触发:
set(obj) { // 根据业务逻辑判断对象是否重复,比如对比order或geojson的唯一标识 const isExist = StoreTest.state.array.some(item => item.order === obj.order); if (!isExist) { StoreTest.state.array.push(obj); } }
- 针对性监听特定属性:如果只关心数组长度或特定元素的属性变化,可以直接监听这些目标,避免深度监听带来的不必要触发。
内容的提问来源于stack exchange,提问作者Amr
相关产品推荐
相关产品推荐

