如何阻止watch函数被数据数组中选中项以外的键触发?
如何阻止watch函数被数据数组中选中项以外的键触发?
问题原因
你当前的代码里,用toRef(() => state.value.data[0].name)创建的引用,实际上会追踪整个state.value.data数组的响应式变化。因为数组是响应式对象,修改数组内任意元素的属性都会触发数组的依赖更新,导致这个toRef的回调被重新执行,进而误触发监听key0Name的watch函数。
解决方案
方案1:直接在watch中传入监听函数(最推荐)
直接把要监听的属性通过函数返回给watch,Vue会精准追踪这个单个属性的变化,不会被数组其他元素的修改影响:
import { useSessionStorage, watch } from "@vueuse/core"; const defaultState = { data: [ { key: 1, name: "A" }, { key: 2, name: "D" }, { key: 3, name: "C" }, ] } const state = useSessionStorage("settings", defaultState, { mergeDefaults: true, }); // 直接监听目标属性的函数返回值 watch( () => state.value.data[0].name, (newOpts) => { console.log("key0Name", newOpts); } ); state.value.data[0].name = "Z" // 正常触发watch state.value.data[1].name = "Z" // 不会触发watch
方案2:用computed包裹目标属性
如果需要多次使用key0Name这个值,可以用computed创建一个仅依赖目标属性的计算属性,再监听这个计算属性:
import { useSessionStorage, watch, computed } from "@vueuse/core"; const defaultState = { data: [ { key: 1, name: "A" }, { key: 2, name: "D" }, { key: 3, name: "C" }, ] } const state = useSessionStorage("settings", defaultState, { mergeDefaults: true, }); const key0Name = computed(() => state.value.data[0].name); watch(key0Name, (newOpts) => { console.log("key0Name", newOpts); }); state.value.data[0].name = "Z" // 正常触发watch state.value.data[1].name = "Z" // 不会触发watch
方案3:使用deep监听+条件判断(不推荐)
这种方式会监听整个数组的深层变化,然后在回调里判断是否是目标属性发生了改变。缺点是效率较低,因为数组任何元素的任何属性变化都会触发watch回调:
import { useSessionStorage, watch } from "@vueuse/core"; const defaultState = { data: [ { key: 1, name: "A" }, { key: 2, name: "D" }, { key: 3, name: "C" }, ] } const state = useSessionStorage("settings", defaultState, { mergeDefaults: true, }); watch( () => state.value.data, (newData, oldData) => { // 仅当目标属性变化时执行逻辑 if (newData[0].name !== oldData[0].name) { console.log("key0Name", newData[0].name); } }, { deep: true } // 开启深层监听 ); state.value.data[0].name = "Z" // 正常触发逻辑 state.value.data[1].name = "Z" // 触发watch但不执行逻辑
总结
优先选择方案1或方案2,它们能精准追踪目标属性的变化,避免不必要的watch触发,性能更好。方案3仅适合特殊场景下的临时处理。
内容的提问来源于stack exchange,提问作者BAR
相关产品推荐
相关产品推荐

