深入理解Vue3中的watch与watchEffect的使用与区别

导图大纲

watch

侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数。

watch() 默认是懒侦听的,即仅在侦听源发生变化时才执行回调函数。

watch 有三个参数

第一个参数:

第一个参数是侦听器的源

  • 一个函数,返回一个值
  • 一个 ref
  • 一个响应式对象
  • ...或是由以上类型的值组成的数组

第二个参数

第二个参数是在发生变化时要调用的回调函数。 这个回调函数接受三个参数:新值、旧值,以及一个用于注册副作用清理的回调函数。 该回调函数会在副作用下一次重新执行前调用,可以用来清除无效的副作用,例如等待中的异步请求。

当侦听多个来源时,回调函数接受两个数组,分别对应来源数组中的新值和旧值。

typescript 复制代码
watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {
  /* ... */
})

第三个参数

第三个可选的参数是一个对象;

  • immediate:在侦听器创建时立即触发回调。第一次调用时旧值是 undefined。
  • deep :如果源是对象,强制深度遍历,以便在深层级变更时触发回调。参考深层侦听器
  • flush :调整回调函数的刷新时机。参考回调的刷新时机watchEffect()
  • onTrack / onTrigger :调试侦听器的依赖。参考调试侦听器

注意

当直接侦听一个响应式对象时,侦听器会自动启用深层模式:

typescript 复制代码
const state = reactive({ count: 0 })
watch(state, () => {
  /* 深层级变更状态所触发的回调 */
})

侦听一个 getter 函数:

当 侦听 一个 getter 函数时,回调只在此函数的返回值变化时才会触发,。 如果想让深层对象变化时,也被侦听调用,可以加 { deep: true } 强制侦听器进入深层级模式

typescript 复制代码
const state = reactive({ count: 0 })
watch(
  () => state.count,
  (count, prevCount) => {
    /* ... */
  },
  {
    deep: true
  }
)

侦听 一个 ref

typescript 复制代码
const count = ref(0)
watch(count, (count, prevCount) => {
  /* ... */
})

watchEffect()

立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行

watchEffect 接受两个参数

第一个参数

第一个参数是数据发生变化时执行的回调函数

  • 当监听的值发生变化时,会自动再次执行以下回调函数
typescript 复制代码
watchEffect(() => {
    //监听objData.str
    console.log(objData.str)
    // 会在 props 变化时打印
    console.log(name, phone, age)
    //海军 1234567 22
  })

第二个参数

第二个参数是一个可选的对象,支持 flush 和 onTrack / onTrigger 选项,功能和 watch 相同。

typescript 复制代码
watchEffect(() => {}, {
  flush: 'post',
  onTrack(e) {
    debugger
  },
  onTrigger(e) {
    debugger
  }
})

停止监听

typescript 复制代码
const stop = watchEffect(() => {})

// 当不再需要此侦听器时:
stop()

注意

注意:watchEffect 仅会在其同步执行期间,才追踪依赖。使用异步回调时,只有在第一个 await 之前访问到的依赖才会被追踪。

watch vs watchEffect

两者区别

watch 和 watchEffect 都能响应式地执行有副作用的回调。它们之间的主要区别是追踪响应式依赖的方式:

  • watch 只追踪明确侦听的数据源。它不会追踪任何在回调中访问到的东西。另外,仅在数据源确实改变时才会触发回调。watch 会避免在发生副作用时追踪依赖,因此,我们能更加精确地控制回调函数的触发时机

  • watchEffect,则会在副作用发生期间追踪依赖。它会在同步执行过程中,自动追踪所有能访问到的响应式属性。这更方便,而且代码往往更简洁,但有时其响应性依赖关系会不那么明确

访问 Vue 更新之后的 DOM

在 Vue2.x 中, 使用 nextTick, 在Vue3 中,watch / watchEffect 指明 flush: 'post' 选项 即可。

typescript 复制代码
watch(source, callback, {
  flush: 'post'
})

watchEffect(callback, {
  flush: 'post'
})

watchEffect 有个别名 也可以 后置刷新 watchPostEffect();

typescript 复制代码
import { watchPostEffect } from 'vue'

watchPostEffect(() => {
  /* 在 Vue 更新后执行 */
})

小技巧

关闭监听器

手动停止一个侦听器,请调用 watch 或 watchEffect 返回的函数:

typescript 复制代码
const stopWatchEffect = watchEffect(() => {
})


stopWatchEffect()



const stopWatch = watch(() => {
})


stopWatch()

异步数据加载

如果需要等待一些异步数据,你可以使用条件式的侦听逻辑:

typescript 复制代码
// 需要异步请求得到的数据
const data = ref(null)

watchEffect(() => {
  if (data.value) {
    // 数据加载后执行某些操作...
  }
})
相关推荐
jacGJ6 小时前
记录学习--文件读写
java·前端·学习
毕设源码-赖学姐7 小时前
【开题答辩全过程】以 基于WEB的实验室开放式管理系统的设计与实现为例,包含答辩的问题和答案
前端
幻云20107 小时前
Python深度学习:从筑基到登仙
前端·javascript·vue.js·人工智能·python
我即将远走丶或许也能高飞9 小时前
vuex 和 pinia 的学习使用
开发语言·前端·javascript
钟离墨笺9 小时前
Go语言--2go基础-->基本数据类型
开发语言·前端·后端·golang
爱吃泡芙的小白白9 小时前
Vue 3 核心原理与实战:从响应式到企业级应用
前端·javascript·vue.js
卓怡学长10 小时前
m115乐购游戏商城系统
java·前端·数据库·spring boot·spring·游戏
老陈聊架构10 小时前
『AI辅助Skill』掌握三大AI设计Skill:前端独立完成产品设计全流程
前端·人工智能·claude·skill
Ulyanov11 小时前
从桌面到云端:构建Web三维战场指挥系统
开发语言·前端·python·tkinter·pyvista·gui开发
cypking11 小时前
二、前端Java后端对比指南
java·开发语言·前端