基于本文回答

播面 播面

文图音视,全方位拆解八股文
0
评论

watch 和 watchEffect 的区别是什么

知识点图片

在 Vue 3 中,watchwatchEffect 都是用于响应式数据的副作用(Side Effect)处理工具(即当数据变化时执行某些操作),但它们在依赖追踪方式执行时机获取数据上有着明显的区别。

以下是它们的核心区别总结:

1. 依赖追踪方式 (核心区别)

  • watch (显式指定依赖):
    • 你需要明确告诉它要监听哪个数据源(ref, reactive 对象, getter 函数或数组)。
    • 它不会追踪回调函数内部访问的变量,只追踪你显式传入的第一个参数。
  • watchEffect (自动/隐式收集依赖):
    • 你不需要指定监听谁。
    • 它会自动追踪回调函数内部用到的所有响应式数据。只要函数里用到了某个 ref,该 ref 变化时函数就会重新执行。

2. 执行时机 (初始化)

  • watch (懒执行 - Lazy):
    • 默认情况下,它不会在组件渲染时立即执行。只有当监听的数据源发生变化时,回调函数才会执行。
    • 注:可以通过配置 { immediate: true } 让其立即执行。
  • watchEffect (立即执行 - Eager):
    • 它在初始化时立即执行一次。这是必须的,因为它需要运行一次代码来知道里面到底用到了哪些数据(从而收集依赖)。

3. 获取新旧值

  • watch:
    • 回调函数接收两个参数:(newValue, oldValue)
    • 你可以很方便地拿到变化前后的值,适合做数据比对。
  • watchEffect:
    • 回调函数不接收 newValueoldValue
    • 它只负责“当依赖变了,我就重跑一遍”,不关心具体是哪个值变了或者变成了什么。

代码对比示例

假设我们有两个响应式数据 countname

使用 watch

javascript
import { ref, watch } from 'vue'

const count = ref(0)

// 1. 必须显式传入要监听的源 (count)
// 2. 默认不执行,只有 count 变了才打印
// 3. 可以拿到新旧值
watch(count, (newVal, oldVal) => {
  console.log(`Count 变了: 从 ${oldVal} 变为 ${newVal}`)
})

使用 watchEffect

javascript
import { ref, watchEffect } from 'vue'

const count = ref(0)
const name = ref('Vue')

// 1. 不需要传入源
// 2. 立即执行一次打印日志
// 3. 自动追踪:如果在里面用了 count 和 name,任意一个变化都会触发重新执行
watchEffect(() => {
  console.log(`当前状态: ${name.value} - ${count.value}`)
})

详细对比表

特性 watch watchEffect
依赖来源 显式指定 (第一个参数) 自动收集 (函数内用到的响应式数据)
首次执行 懒执行 (数据变化时才跑) 立即执行 (组件加载时先跑一次)
访问旧值 支持 (newValue, oldValue) 不支持
深度监听 监听 Ref 默认为浅层 (需 deep: true)
监听 Reactive 对象默认为深层
自动追踪访问到的属性 (看起来像深层)
适用场景 需要旧值、需要精确控制触发时机、只需监听特定数据 逻辑依赖多个数据、初始化就需要执行、不在乎旧值

什么时候用哪个?

  1. 使用 watchEffect 的场景:

    • 当你有一个逻辑依赖于多个响应式数据,且你不想要把它们一个个列出来时。
    • 例如:根据 userIdfilter 自动发起网络请求获取数据(请求通常需要立即发起一次,且参数变了要重新发起)。
  2. 使用 watch 的场景:

    • 当你需要比较数据的前一个值当前值时。
    • 当你希望在数据变化时执行操作,但不希望在初始化时执行
    • 当你只想监听某个特定数据的变化,而忽略回调函数内部使用的其他响应式数据时(避免不必要的触发)。

总结

  • watch 更像 Vue 2 的 this.$watch,更加精确和可控
  • watchEffect 更像 React 的 useEffect(不带依赖数组版)或 Vue 的 computed(但是没有返回值),更加智能和简洁
00:00
00:00