vue3中Watch和WatchEffect的用法和区别

news2025/2/25 16:11:02

目录

Ⅰ.Watch

1.基本用法和三个参数的解析

(1).参数1:需要监听的数据源

(2).参数2:当监听数据发生变化时需要执行的回调函数

(3).参数3:配置选项

深层监听器(多种形式):

关于watch的返回值问题:

Ⅱ .WatchEffect

1.基本用法和两个参数的解析

Ⅲ.watch vs watchEffect


Ⅰ.Watch

1.基本用法和三个参数的解析

当我们需要在数据变化时执行一些“副作用”/监听数据变化时:如更改 DOM、执行异步操作等,就可以使用 watch 函数。

watch(参数1,参数2,参数3) 一共可以有三个参数,分别是:需要监听的数据源、需要执行的回调函数、watch的配置选项。

(1).参数1:需要监听的数据源

watch()的第一个参数可以是不同形式(即不同类型)的“数据源”,它可以是:

  • 一个 ref 响应式数据
  • 一个计算属性
  • 一个 (getter) 函数(有返回值的函数)
  • 一个 reactive 响应式数据对象
  • 以上类型的值组成的数组 / 多个相同类型数据组成的数组
const x = ref(1)
const y = ref(2)
const doubleX = computed(() => x.value * 2)
const obj = reactive({ count: 0 })

// 监听一个 ref 数据
watch(x, (newValue) => {
  console.log(`x is ${newValue}`)
})

// 监听计算属性doubleX
watch(doubleX, (newValue) => {
  console.log(`doubleX is ${newValue}`)
})

// 监听一个 (getter) 函数
watch(
  () => x.value + y.value,
  (sum) => {
    console.log(`sum of x + y is: ${sum}`)
  }
)

// 监听一个 reactive 类型的数据(响应式对象obj)
watch(obj, (newValue, oldValue) => {
  // 在嵌套的属性变更时触发
  // 注意:`newValue` 此处和 `oldValue` 是相等的
  // 因为它们是同一个对象!
})

// 监听由以上多个数据类型的值组成的数组
watch([x, () => y.value], ([newX, newY]) => {
  console.log(`x is ${newX} and y is ${newY}`)
})

注意,你不能直接侦听响应式对象的属性值,例如:

const obj = reactive({ count: 0 })

// 错误,因为 watch() 此时得到的参数是一个 number
watch(obj.count, (count) => {
  console.log(`count is: ${count}`)
})

这里需要用一个返回该属性的 (getter) 函数

watch(
  () => obj.count, // 提供一个 getter 函数返回要监听的这个属性值
  (count) => {
    console.log(`count is: ${count}`)
  }
)

(2).参数2:当监听数据发生变化时需要执行的回调函数

watch()的第二个参数是数据发生变化时执行的回调函数。

这个回调函数也接受三个参数:新值(newValue)、旧值(oldValue),以及一个用于清理副作用的回调函数(onCleanup)。onCleanup()回调函数会在副作用下一次执行前调用,可以用来清除无效的副作用,如等待中的异步请求。

const id = ref(1)
const data = ref(null)

watch(id, async (newValue, oldValue, onCleanup) => {
  const { response, cancel } = doAsyncWork(id.value)
  // `cancel` 会在 `id` 更改时调用
  // 以便取消之前未完成的请求
  onCleanup(cancel)
  data.value = await response.json()
})

(3).参数3:配置选项

watch()的第三个参数是一个可选的对象{...},可以添加以下一个/多个选项:

  • immediate:在侦听器创建时立即触发回调。
    因为 watch() 函数是懒执行的:即当数据源发生变化时,才会执行回调。但在某些场景中,我们希望在创建侦听器时,立即执行一遍回调。所以我们可以使用 immediate 选项来实现立即监听。
  • deep:深度遍历,以便在深层级变更时触发回调。
  • flush:回调函数的触发时机,它有以下三个值:
    pre:默认,dom 更新前调用
    post:dom 更新后调用
    sync:同步调用
  • onTrack / onTrigger:用于调试的钩子。在依赖收集和回调函数触发时被调用。
watch(
  () => obj.someObject,
  (newValue, oldValue) => {
    // `newValue` 此处和 `oldValue` 是相等的,除非 obj.someObject 被整个替换了
    console.log('deep', newValue.count, oldValue.count)
  },
  {  
    deep: true,    //开启深度监听
    immediate: true    //开启立即监听(第一次就监听)
    //flush: 'post'    //如果想要在回调函数里面获取更新后的DOM,就可以添加这一项
  }
)

obj.someObject.count++ //打印结果: 'deep' 1 1

深层监听器(多种形式):

直接给 watch() 传入一个响应式对象(即监听的数据源),会默认创建一个深层侦听器:所有嵌套的属性变更时都会被触发

const obj = reactive({ count: 0 })

watch(obj, (newValue, oldValue) => {
  // 在嵌套的属性变更时触发
  // 注意:`newValue` 此处和 `oldValue` 是相等的
  // 因为它们是同一个对象!
})

obj.count++

 相比之下,如果监听的是一个返回响应式对象的 getter 函数只有在对象被替换时才会触发:

const obj = reactive({
  someString: 'hello',
  someObject: { count: 0 }
})

watch(
  () => obj.someObject,
  () => {
    // 仅当 obj.someObject 被替换时才会触发这个回调函数
  }
)

我们也可以自己手动显式地加上 deep 选项,强制将watch()变为深层监听器(即深度监听):

watch(
  () => obj.someObject,
  (newValue, oldValue) => {
    // `newValue` 此处和 `oldValue` 是相等的,除非 obj.someObject 被整个替换了
    console.log('deep', newValue.count, oldValue.count)
  },
  { deep: true }
)

obj.someObject.count++ // 打印 'deep' 1 1

但是,深层监听一个响应式对象或数组,新值和旧值是相等的。为了解决这个问题,我们可以对值进行深拷贝

watch(
  //对监听的值进行深拷贝,确保你安装了lodash
  () => _.cloneDeep(obj.someObject),
    
  (newValue, oldValue) => {
    // 此时 `newValue` 此处和 `oldValue` 是不相等的
    console.log('deep', newValue.count, oldValue.count)
  },
  { deep: true }
)

obj.someObject.count++ //打印 'deep' 1 0

注意:深层侦听需要遍历所有嵌套的属性,当数据结构庞大时,开销很大。所以我们要谨慎使用,并且留意性能。

关于watch的返回值问题:

watch 的返回值是一个用来停止该副作用的函数,我们需要用一个变量接收监听器函数的返回值,其实就是返回的一个函数,然后我们调用该函数,即可关闭当前监听器。示例如下:

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

// ...当该侦听器不再需要时
unwatch()

注意:使用同步语句创建的侦听器,会自动绑定到宿主组件实例上,并且会在宿主组件卸载时自动停止。使用异步回调创建一个侦听器,则不会绑定到当前组件上,我们必须手动停止它,以防内存泄漏。示例如下:

<script setup>
import { watchEffect } from 'vue'

// 同步创建,组件卸载会自动停止
watchEffect(() => {})

// 异步创建,组件卸载不会停止,需要手动停止
setTimeout(() => {
  watchEffect(() => {})
}, 100)
</script>

Ⅱ .WatchEffect

1.基本用法和两个参数的解析

watchEffect 相比于 watch 会立即监听(创建监听器时就监听)并执行一遍回调函数,如果这时函数产生了副作用,Vue 会自动追踪副作用的依赖关系,自动分析出侦听数据源。
watchEffect 接受两个参数:

第一个参数是数据发生变化时执行的回调函数,用法和 watch 一样。

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

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

 假设有一个watch监听代码如下:

const url = ref('https://...')
const data = ref(null)

async function fetchData() {
  const response = await fetch(url.value)
  data.value = await response.json()
}

// 立即执行一次,再侦听 url 变化
watch(url, fetchData, { immediate: true })

 那我们就可以用watchEffect监听改写如以下代码:

const url = ref('https://...')
const data = ref(null)

// 一个参数就可以搞定
watchEffect(async () => {
  const response = await fetch(url.value)
  data.value = await response.json()
})

Ⅲ.watch vs watchEffect

watch 和 watchEffect 的主要功能是相同的,都能响应式地执行回调函数。它们的区别是追踪响应式依赖的方式不同:

  • watch 只追踪明确定义的数据源,不会追踪在回调中访问到的东西;默认情况下,只有在数据源发生改变时才会触发回调;watch 可以访问侦听数据的新值和旧值。
  • watchEffect会初始化执行一次,在副作用发生期间追踪依赖,自动分析出侦听数据源;watchEffect 无法访问侦听数据的新值和旧值。

简单一句话,watch 功能更加强大,而 watchEffect 在某些场景下更加简洁。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2304955.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

三、《重学设计模式》-单例模式

单例模式 单例模式分为四大类&#xff0c;饿汉式、懒汉式、静态内部类、枚举 饿汉式 优点&#xff1a;类装载时进行实例化&#xff0c;避免同步问题 缺点&#xff1a;造成内存浪费 实现一 1.构造器私有化 2.内部创建对象实例 3.提供静态方法 public class Type1 {public s…

SpringBoot3整合Swagger3时出现Type javax.servlet.http.HttpServletRequest not present错误

目录 错误详情 错误原因 解决方法 引入依赖 修改配置信息 创建文件 访问 错误详情 错误原因 SpringBoot3和Swagger3版本不匹配 解决方法 使用springdoc替代springfox&#xff0c;具体步骤如下&#xff1a; 引入依赖 在pom.xml文件中添加如下依赖&#xff1a; <…

项目实战--网页五子棋(匹配模块)(4)

上期我们完成了游戏大厅的前端部分内容&#xff0c;今天我们实现后端部分内容 1. 维护在线用户 在用户登录成功后&#xff0c;我们可以维护好用户的websocket会话&#xff0c;把用户表示为在线状态&#xff0c;方便获取到用户的websocket会话 package org.ting.j20250110_g…

【Java毕业设计】商城购物系统(附源码+数据库脚本)

本系统是基于JavaEEServletJSPMysql实现的商城购物系统。包括用户登录、用户注册、商品分类、添加购物车、订单支付等基本功能&#xff0c;具体页面及功能如下&#xff1a; 感谢阅读&#xff01; 如需获取完整项目源码及更多项目信息&#xff0c;可添加V&#xff1a;

POST请求提交数据的三种方式及通过Postman实现

1、什么是POST请求&#xff1f; POST请求是HTPP协议中一种常用的请求方法&#xff0c;它的使用场景是向客户端向服务器提交数据&#xff0c;比如登录、注册、添加等场景。另一种常用的请求方法是GET&#xff0c;它的使用场景是向服务器获取数据。 2、POST请求提交数据的常见编…

Spring Boot 整合 Spring MVC /(整合Web)笔记

1. Spring Boot 整合 Web 功能 Spring Boot 通过自动配置简化了 Spring MVC 的集成。只需在 pom.xml 中添加 spring-boot-starter-web 依赖&#xff0c;Spring Boot 就会自动配置 Spring MVC 的相关组件。 <dependency><groupId>org.springframework.boot</gr…

[特殊字符]清华大学:DeepSeek从入门到精通.pdf(清华领航,驾驭DeepSeek,开启AI新境界)

不愧是清华大学出品的deepseek手册&#xff0c;简直是新手 福音&#xff0c;非常实用&#xff01; 这份《DeepSeek&#xff1a;从入门到精通》手册从基础到高 阶&#xff0c;手把手教你玩转DeepSeek&#xff0c;特别适合刚入门的小白&#xff0c;拿来就能用&#xff01; 1.Deep…

深度学习技术全景图:从基础架构到工业落地的超级进化指南

&#x1f50d; 目录导航 基础架构革命训练优化秘技未来战场前瞻 &#x1f9e9; 一、基础架构革命 1.1 前馈神经网络&#xff08;FNN&#xff09; ▍核心结构 import torch.nn as nnclass FNN(nn.Module):def __init__(self):super().__init__()self.fc1 nn.Linear(784, 25…

PyTorch-基础(CUDA、Dataset、transforms、卷积神经网络、VGG16)

PyTorch-基础 环境准备 CUDA Toolkit安装&#xff08;核显跳过此步骤&#xff09; CUDA Toolkit是NVIDIA的开发工具&#xff0c;里面提供了各种工具、如编译器、调试器和库 首先通过NVIDIA控制面板查看本机显卡驱动对应的CUDA版本&#xff0c;如何去下载对应版本的Toolkit工…

IO/网络IO基础全览

目录 IO基础CPU与外设1. 程序控制IO&#xff08;轮询&#xff09;2. 中断中断相关知识中断分类中断处理过程中断隐指令 3. DMA&#xff08;Direct Memory Access&#xff09; 缓冲区用户空间和内核空间IO操作的拷贝概念传统IO操作的4次拷贝减少一个CPU拷贝的mmap内存映射文件(m…

【DeepSeek-R1背后的技术】系列十一:RAG原理介绍和本地部署(DeepSeekR1+RAGFlow构建个人知识库)

【DeepSeek-R1背后的技术】系列博文&#xff1a; 第1篇&#xff1a;混合专家模型&#xff08;MoE&#xff09; 第2篇&#xff1a;大模型知识蒸馏&#xff08;Knowledge Distillation&#xff09; 第3篇&#xff1a;强化学习&#xff08;Reinforcement Learning, RL&#xff09;…

鸿蒙开发深入浅出04(首页数据渲染、搜索、Stack样式堆叠、Grid布局、shadow阴影)

鸿蒙开发深入浅出04&#xff08;首页数据渲染、搜索、Stack样式堆叠、Grid布局、shadow阴影&#xff09; 1、效果展示2、ets/pages/Home.ets3、ets/views/Home/SearchBar.ets4、ets/views/Home/NavList.ets5、ets/views/Home/TileList.ets6、ets/views/Home/PlanList.ets7、后端…

【数据结构】B树家族详解:B树、B+树、B*

一、B树(B-Tree) 1. 定义 B树是一种平衡多路查找树,自平衡的树,能够保持数据有序,设计目标是为减少磁盘I/O次数。适用于需要频繁读写磁盘的场景(如数据库、文件系统)。 2、B树基本性质 节点键值数量限制: 对于 m 阶 B 树,根节点至少有 1 个键值,最多有 m - 1 个…

C语言数据结构—二叉树的链式结构实现

目录 1、建立二叉树 1.1 二叉树的结构 1.2 手动建立二叉树 2、二叉树的遍历 2.1 二叉树的三种遍历方式 2.1.1 前序遍历 2.1.2 中序遍历 2.1.2 后序遍历 3、求二叉树的结点数和二叉树的高度 3.1 求二叉树结点数 3.2 求二叉树叶子结点 3.3 求二叉树第k层结点的个数 …

Java 大视界 —— Java 大数据在智能零售动态定价策略中的应用实战(98)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

危化品经营单位安全管理人员的职责及注意事项

危化品经营单位安全管理人员肩负着保障经营活动安全的重要责任&#xff0c;以下是其主要职责及注意事项&#xff1a; 职责 1. 安全制度建设与执行&#xff1a;负责组织制定本单位安全生产规章制度、操作规程和生产安全事故应急救援预案&#xff0c;确保这些制度符合国家相关法…

Day 49 卡玛笔记

这是基于代码随想录的每日打卡 1143. 最长公共子序列 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变…

WebXR教学 01 基础介绍

什么是WebXR&#xff1f; 定义 XR VR AR Web上使用XR技术的API WebXR 是一组用于在 Web 浏览器中实现虚拟现实&#xff08;VR&#xff09;和增强现实&#xff08;AR&#xff09;应用的技术标准。它由 W3C 的 Immersive Web 工作组开发&#xff0c;旨在提供跨设备的沉浸式体验…

DeepSeek+Kimi生成高质量PPT

DeepSeek与Kimi生成PPT全流程解析 一、工具分工原理 DeepSeek核心作用&#xff1a;生成结构化PPT大纲&#xff08;擅长逻辑构建与内容优化&#xff09;Kimi核心作用&#xff1a;将文本转换为视觉化PPT&#xff08;提供模板库与排版引擎&#xff09; 二、操作步骤详解 1. 通…

clickhouse--表引擎的使用

表引擎决定了如何存储表的数据。包括&#xff1a; 数据的存储方式和位置&#xff0c;写到哪里以及从哪里读取数据。(默认是在安装路径下的 data 路径)支持哪些查询以及如何支持。&#xff08;有些语法只有在特定的引擎下才能用&#xff09;并发数据访问。索引的使用&#xff0…