You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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 });
}

原因分析
  1. deep: true的深度监听逻辑:你给watch开了深度监听,Vue会递归检查数组的内部变化。哪怕数组引用没变,只要调用push修改了数组的长度、内部元素位置,深度监听都会捕捉到这个变更,触发回调。
  2. 数组变异方法的响应式拦截:Vue对数组的push/pop/sort等变异方法做了特殊拦截,只要调用这些方法修改数组,不管添加的元素是不是重复对象,都会触发依赖更新,而你的watch会响应这个更新。
  3. 对象相同不等于引用相同:就算你添加的对象内容完全一致,每次调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 21:23:16