关于vue3.2父子组件传ref数组监听问题?

代码demo:

// 父组件
html:
<comp v-model:tableData="tableData"></comp>
js:
let tableData = ref([]);
// 获取评论列表
async function getCommentList() {
    let res = await api();
    tableData.value = res.data
}

// 子组件
js:
const props = defineProps({
  tableData: {
    type: Array,
    default: () => [],
  }
});
watch(
  ()=>props.tableData,// 为什么这里不加()=>就无法进入监听?
  (newVal) => {...},
  { deep: true }
);

请教一下子组件的watch不加()=>就无法进入监听?

阅读 1.1k
avatarAI BotBETA

在 Vue 3 中,watch 是一个用于观察和响应 Vue 实例上的数据变化的 API。它允许你在数据变化时执行一些自定义逻辑。

对于你的问题,watch 函数的第一个参数应该是一个依赖项数组,该数组包含了你想要观察的响应式属性。在这个数组中,你可以直接使用变量名(对于局部响应式属性)或 this.$refs(对于子组件的响应式属性)。

在你的代码中,你正在尝试观察一个从父组件传递到子组件的 prop,即 tableData。由于 tableData 是通过 prop 传递的,它不是子组件的局部响应式属性。因此,你不能直接将其放入依赖项数组中。

解决这个问题的一种方法是使用箭头函数。箭头函数可以捕获定义它们的作用域中的变量,这意味着你可以在箭头函数中使用 props.tableData,而不是直接在 watch 函数中使用它。这样,当 tableData 发生变化时,箭头函数将返回新的值,从而使 watch 进入监听模式。

下面是修改后的代码:

// 子组件
const props = defineProps({
  tableData: {
    type: Array,
    default: () => [],
  }
});
watch(
  () => props.tableData, // 使用箭头函数捕获props.tableData
  (newVal) => {
    // 当 tableData 发生变化时执行的逻辑
  },
  { deep: true }
);

现在,当 tableData 发生变化时,watch 将进入监听模式,并执行你提供的回调函数。

2 个回答

根据官方的API说明:

watch(WatcherSource, Callback, [WatchOptions])

type WatcherSource<T> = Ref<T> | (() => T) 

interface WatchOptions extends WatchEffectOptions {
    deep?: boolean // 默认:false 
    immediate?: boolean // 默认:false 
    flush?: string // 默认:'pre'
}

因此你应该:

watch(
  tableData,
  (newVal) => {...},
  { deep: true }
);

最后提醒一下:

当我们使用watch侦听引用对象时

  • 若使用ref定义的引用对象:

    • 只要获取当前值,watch第一个参数直接写成数据源,另外需要加上deep:true选项
    • 若要获取当前值和先前值,需要把数据源写成getter函数的形式,并且需对数据源进行深拷贝
  • 若使用reactive定义的引用对象:

    • 只要获取当前值,watch第一个参数直接写成数据源,可以不加deep:true选项
    • 若要获取当前值和先前值,需要把数据源写成getter函数的形式,并且需对数据源进行深拷贝

这个问题感觉主要是

watch(
  ()=>props.tableData,
  (newVal) => {...},
  { deep: true }
);

watch(
  props.tableData
  (newVal) => {...},
  { deep: true }
);

的区别,因为props.tableData并非是一个响应式值,所以不能监听。

而Vue 将你提供的函数 () => props.view 转换为一个响应式效果。这个效果会在适当的时机被重新执行,比如响应式依赖发生变化时。

当你执行 watch(() => props.view, callback) 时,你实际上做了以下几件事情:

创建响应式效果:Vue 将你提供的函数 () => props.view 转换为一个响应式效果。这个效果会在适当的时机被重新执行,比如响应式依赖发生变化时。

收集依赖:当 Vue 执行这个响应式效果(即你提供的函数)时,它会跟踪这个函数执行过程中访问到的所有响应式属性。在这个例子中,函数访问了 props.view,因此 props.view 就被当作一个依赖收集起来。

重新执行和比较:当依赖(在这个例子中是 props.view)的值发生变化时,Vue 会重新执行这个响应式效果,并获取新的返回值。然后,Vue 会比较新值和旧值,如果它们不同,就会调用你提供的回调函数。

推荐问题
宣传栏