joken-前端工程师

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: :: :: 管理 ::
  404 随笔 :: 39 文章 :: 8 评论 :: 20万 阅读

在 Vue 3 中,watch 函数提供了强大的监听功能,可以监听响应式数据的变化。默认情况下,watch 并不会进行深度监听,也就是说它只会检测到对象或数组的直接替换,而不会检测到其内部属性或元素的变化。如果你需要对对象或数组进行深度监听,可以通过设置 deep 选项来实现。

基本用法

假设你有一个响应式的对象或数组,并希望监听它的变化:

import { reactive, watch } from 'vue';

const state = reactive({
  nested: {
    count: 0
  }
});

普通监听(非深度监听)

仅监听整个对象是否发生变化:

watch(() => state.nested, (newVal, oldVal) => {
  console.log('state.nested changed:', newVal, oldVal);
});

在这个例子中,只有当 state.nested 被整个替换时,监听器才会触发。

深度监听

如果希望监听对象内部任何层级的变化,需要设置 deep: true

watch(() => state.nested, (newVal, oldVal) => {
  console.log('state.nested deep changed:', newVal, oldVal);
}, { deep: true });

这样,即使 state.nested.count 发生了变化,监听器也会被触发。

使用 watch 监听多个来源

你可以同时监听多个来源的数据变化,无论是简单的值、对象还是计算属性。例如:

watch([() => state.nested.count, () => state.nested.name], ([newCount, newName], [oldCount, oldName]) => {
  console.log('count or name changed:', newCount, newName, oldCount, oldName);
}, { deep: true });

注意事项

  1. 性能考虑:深度监听会增加计算开销,因为它需要递归地检查每个嵌套级别的变化。因此,仅在必要时使用深度监听,并尽量限制监听范围。

  2. 旧值与新值:在深度监听的情况下,Vue 可能无法提供真正的旧值和新值对比,因为 Vue 实际上是在比较两个不同的对象引用。这意味着 oldValnewVal 可能是相同的对象引用,特别是在浅层比较时。

  3. 清理副作用:如果你在监听器内执行异步操作或其他有副作用的操作,请确保在组件卸载前清理这些副作用,以避免内存泄漏。可以通过返回一个清理函数来实现:

    const stopWatch = watch(() => state.nested, (newVal, oldVal) => {
      const timer = setTimeout(() => {
        console.log('Asynchronous operation after state change');
      }, 1000);
    
      return () => clearTimeout(timer); // 清理定时器
    }, { deep: true });
    
    // 当不再需要监听时
    stopWatch();
    

通过合理使用 watch 的深度监听功能,你可以更精确地控制你的应用逻辑,并有效地响应复杂状态的变化。

watchEffect

在 Vue 3 中,watchEffect 是一个非常强大的函数,用于自动追踪响应式依赖并立即执行副作用。与 watch 不同,watchEffect 会自动收集其内部使用的响应式数据作为依赖项,并在这些依赖项发生变化时重新运行。

默认行为

关于深度监听,watchEffect 的一个重要特点是它默认会进行深度监听,但这种“深度监听”是基于它自动追踪到的所有响应式依赖,而不是像 watch 那样通过显式的 deep: true 选项来实现的。

具体来说:

  • 当你在 watchEffect 内部访问某个响应式对象或数组的属性时,Vue 会自动追踪这些属性的变化。
  • 如果你修改了对象或数组内部的任何属性,watchEffect 会检测到变化并重新运行。

示例

假设你有一个嵌套的响应式对象:

import { reactive, watchEffect } from 'vue';

const state = reactive({
  nested: {
    count: 0,
    details: {
      name: 'Vue'
    }
  }
});

你可以使用 watchEffect 来监听任何对 state.nested 及其子属性的更改:

watchEffect(() => {
  console.log('Current count:', state.nested.count);
  console.log('Name in details:', state.nested.details.name);
});

在这个例子中,如果修改了 state.nested.countstate.nested.details.namewatchEffect 都会自动检测到这些变化并重新运行。

例如:

setTimeout(() => {
  state.nested.count++; // 触发 watchEffect 重新运行
}, 1000);

setTimeout(() => {
  state.nested.details.name = 'Vue 3'; // 同样触发 watchEffect 重新运行
}, 2000);

注意事项

  1. 性能考虑:虽然 watchEffect 自动追踪所有被访问的响应式依赖,但这也意味着它可能会追踪比你实际需要更多的依赖项。因此,在大型应用中,合理控制 watchEffect 的范围和逻辑是很重要的,以避免不必要的计算开销。

  2. 清理副作用:如果你在 watchEffect 内执行了异步操作或其他有副作用的操作,请确保在组件卸载前清理这些副作用,以避免内存泄漏。可以通过返回一个清理函数来实现:

    const stopWatchEffect = watchEffect(() => {
      const timer = setTimeout(() => {
        console.log('Asynchronous operation after state change');
      }, 1000);
    
      return () => clearTimeout(timer); // 清理定时器
    });
    
    // 当不再需要监听时
    stopWatchEffect();
    
  3. 对比 watchwatchEffect

    • watch 提供更细粒度的控制,可以指定要监听的具体数据源,并且可以选择是否启用深度监听。
    • watchEffect 更加自动化,适合于快速实现简单的响应式逻辑,但可能不如 watch 灵活。

总结

watchEffect 在 Vue 3 中默认会自动追踪并监听所有在其作用域内被访问的响应式依赖,这相当于默认进行了深度监听。然而,这种监听方式是基于自动追踪的机制,而不是通过显式的配置选项来实现的。理解这一点可以帮助你更好地利用 watchEffect 来构建响应式的应用逻辑。

posted on   joken1310  阅读(150)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
点击右上角即可分享
微信分享提示