详细讲解vue3 watch回调的触发时机

目录

Vue 3 watch 基本用法

副作用刷新时机

flush 选项

flush: 'pre'

flush: 'post'

flush: 'sync'


Vue 3 watch 基本用法

计算属性允许我们声明性地计算衍生值。然而在有些情况下,我们需要在状态变化时执行一些“副作用”:例如更改 DOM,或是根据异步操作的结果去修改另一处的状态。

在组合式 API 中,我们可以使用 watch 函数在每次响应式状态发生变化时触发回调函数:

<script setup>
import { ref, watch } from 'vue'const question = ref('')
const answer = ref('Questions usually contain a question mark. ;-)')
const loading = ref(false)// 可以直接侦听一个 ref
watch(question, async (newQuestion, oldQuestion) => {if (newQuestion.includes('?')) {loading.value = trueanswer.value = 'Thinking...'try {const res = await fetch('https://yesno.wtf/api')answer.value = (await res.json()).answer} catch (error) {answer.value = 'Error! Could not reach the API. ' + error} finally {loading.value = false}}
})
</script><template><p>Ask a yes/no question:<input v-model="question" :disabled="loading" /></p><p>{{ answer }}</p>
</template>

副作用刷新时机

Vue 的响应性系统会缓存副作用函数,并异步地刷新它们,这样可以避免同一个“tick”中多个状态改变导致的不必要的重复调用。

同一个“tick”的意思是,Vue的内部机制会以最科学的计算规则将视图刷新请求合并成一个一个的"tick",每个“tick”刷新一次视图,比如a=1;b=2;只会触发一次视图刷新。$nextTick的Tick就是指这个。

flush 选项

Vue 3 提供了 flush 选项来控制 watch 回调的执行时机。flush 有三个可选值:prepostsync

flush: 'pre'
  • 触发时机:在响应式依赖项的值更新之前执行回调。

当你更改了响应式状态,它可能会同时触发 Vue 组件更新和侦听器回调。

类似于组件更新,用户创建的侦听器回调函数也会被批量处理以避免重复调用。例如,如果我们同步将一千个项目推入被侦听的数组中,我们可能不希望侦听器触发一千次。

默认情况下,侦听器回调会在父组件更新 (如有) 之后、所属组件的 DOM 更新之前被调用。这意味着如果你尝试在侦听器回调中访问所属组件的 DOM,那么 DOM 将处于更新前的状态。

​<template><div><buttonid="aa"@click="() => {r++s++}">{{ r }} - {{ s }}</button></div>
</template><script>
import { ref, watch } from 'vue'
export default {setup() {let r = ref(2)let s = ref(10)watch([() => s.value, () => r.value], () => {console.log(r.value, s.value)console.log(document.querySelector('#aa') && document.querySelector('#aa').innerText)})return {r,s}}
}
</script>​

 点击若干次(比如2次)按钮,得到的结果是:

 

当我第1和2次点击完,你会发现,document.querySelector('#aa').innerText获取到的总是点击之前DOM的内容。这也说明,默认Vue先执行监听器,所以取到了上一次的内容,然后执行组件update。

 

flush: 'post'
  • 触发时机:在响应式依赖项的值更新之后执行回调。

如果想在侦听器回调中能访问被 Vue 更新之后的所属组件的 DOM,你需要指明 flush: 'post' 选项:

watchEffect(() => {/* ... */},{flush: 'post'}
)
没设flush: 'post'设了flush: 'post'

所以结论是,如果要操作“更新之后的DOM”,就要配置flush: 'post'。
 

后置刷新的 watchEffect() 有个更方便的别名 watchPostEffect()

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

 

flush: 'sync'
  • 触发时机:在数据变化的同步代码块中执行回调。

你还可以创建一个同步触发的侦听器,它会在 Vue 进行任何更新之前触发: 

同步触发的 watchEffect() 有个更方便的别名 watchSyncEffect()

import { watchSyncEffect } from 'vue'watchSyncEffect(() => {/* 在响应式数据变化时同步执行 */
})

 

  • 如果flush设置为“sync”,一旦值发生变化,回调将被同步调用。 
  • 对于“pre”和“post”,回调都使用队列进行缓冲。即使监视值多次更改,回调也只会添加到队列中一次。临时值将被跳过并且不会传递给回调。
  • 缓冲回调不仅可以提高性能,还有助于确保数据一致性。在执行数据更新的代码完成之前,不会触发观察者
  • 应谨慎使用“同步”观察者,因为它们没有这些好处。
  • 适用于需要立即响应数据变化的情况,例如实时计算或紧急数据更新。

谨慎使用

同步侦听器不会进行批处理,每当检测到响应式数据发生变化时就会触发。可以使用它来监视简单的布尔值,但应避免在可能多次同步修改的数据源 (如数组) 上使用。


<script>
import { watch, ref } from 'vue'export default {setup() {const count = ref(0)watch(count,(newVal, oldVal) => {console.log(`count changed from ${oldVal} to ${newVal} (pre)`)},{ flush: 'pre' })watch(count,(newVal, oldVal) => {console.log(`count changed from ${oldVal} to ${newVal} (post)`)},{ flush: 'post' })watch(count, (newVal, oldVal) => {console.log(`count changed from ${oldVal} to ${newVal} (pre)`)})watch(count,(newVal, oldVal) => {console.log(`count changed from ${oldVal} to ${newVal} (sync)`)},{ flush: 'sync' })function increment() {count.value++}return { count, increment }}
}
</script><template><div @click="increment">{{ count }}</div>
</template>
<style scoped></style>

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

display: flex 和 justify-content: center 强大居中

你还在为居中而烦恼吗&#xff0c;水平居中多个元素、创建响应式布局、垂直和水平同时居中内容。它&#xff0c;display: flex 和 justify-content: center 都可以完成&#xff01; display: flex&#xff1a;将元素定义为flex容器 justify-content&#xff1a;定义项目在主轴…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] LYA的生日派对座位安排(200分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题目在线…

FairGuard游戏加固入选《嘶吼2024网络安全产业图谱》

2024年7月16日&#xff0c;国内网络安全专业媒体——嘶吼安全产业研究院正式发布《嘶吼2024网络安全产业图谱》(以下简称“产业图谱”)。 本次发布的产业图谱&#xff0c;共涉及七大类别&#xff0c;127个细分领域。全面展现了网络安全产业的构成和重要组成部分&#xff0c;探…

Ant Design Vue中日期选择器快捷选择 presets 用法

ant写文档的纯懒狗 返回的是一个day.js对象 范围选择时可接受一个数组 具体参考 操作 Day.js 话不多说 直接上代码 <a-range-pickerv-model:value"formData.datePick"valueFormat"YYYY-MM-DD HH:mm:ss"showTime:presets"presets"change&quo…

【机器学习】模型验证曲线(Validation Curves)解析

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 模型验证曲线(Validation Curves)解析什么是模型验证曲线?模型验证曲线的解读模…

揭秘!电源炼成记:从基础原理到高端设计的全面解析

文章目录 初始构想&#xff1a;需求驱动设计原理探索&#xff1a;选择适合的拓扑结构精细设计&#xff1a;元器件选型与布局环路稳定&#xff1a;控制策略与补偿网络严格测试&#xff1a;验证与优化持续改进&#xff1a;创新与技术迭代《硬件十万个为什么&#xff08;电源是怎样…

《Linux运维总结:基于ARM64架构CPU使用docker-compose一键离线部署单机版tendis2.4.2》

总结&#xff1a;整理不易&#xff0c;如果对你有帮助&#xff0c;可否点赞关注一下&#xff1f; 更多详细内容请参考&#xff1a;《Linux运维篇&#xff1a;Linux系统运维指南》 一、部署背景 由于业务系统的特殊性&#xff0c;我们需要面对不同的客户部署业务系统&#xff0…

单周期CPU(三)译码模块(minisys)(verilog)(vivado)

timescale 1ns / 1ps //module Idecode32 (input reset,input clock,output [31:0] read_data_1, // 输出的第一操作数output [31:0] read_data_2, // 输出的第二操作数input [31:0] Instruction, // 取指单元来的指令input [31:0] …

邮件安全篇:企业电子邮件安全涉及哪些方面?

1. 邮件安全概述 企业邮件安全涉及多个方面&#xff0c;旨在保护电子邮件通信的机密性、完整性和可用性&#xff0c;防止数据泄露、欺诈、滥用及其他安全威胁。本文从身份验证与防伪、数据加密、反垃圾邮件和反恶意软件防护、邮件内容过滤与审计、访问控制与权限管理、邮件存储…

MATLAB基础:字符串、元胞数组

今天我们继续学习MATLAB中的字符串、元胞和结构 字符串 由于MATLAB是面向矩阵的&#xff0c;所以字符串的处理可以用矩阵的形式实现 字符串的赋值与引用 假设变量a&#xff0c;将用单引号引起来的字符串赋值给它&#xff0c; a清心明目, b(a[4;-1;1]) 在这里&#xff0c;…

web每日一练

每日一题 每天一题罢了。。 ctfshow内部赛签到 扫到备份文件 login.php <?php function check($arr){ if(preg_match("/load|and|or|\||\&|select|union|\|| |\\\|,|sleep|ascii/i",$arr)){echo "<script>alert(bad hacker!)</script>&q…

Lua 语法学习笔记

Lua 语法学习笔记 安装(windows) 官网&#xff1a;https://www.lua.org/ 下载SDK 解压&修改名称&#xff08;去除版本号&#xff09; 将lua后面的版本号去掉&#xff0c;如lua54.exe->lua.ext 配置环境变量 数据类型 数据类型描述nil这个最简单&#xff0c;只有值n…

【safari】react在safari浏览器中,遇到异步时间差的问题,导致状态没有及时更新到state,引起传参错误。如何解决

在safari浏览器中&#xff0c;可能会遇到异步时间差的问题&#xff0c;导致状态没有及时更新到state&#xff0c;引起传参错误。 PS&#xff1a;由于useState是一个普通的函数&#xff0c; 定义为() > void;因此此处不能用await/async替代setTimeout&#xff0c;只能用在返…

自动驾驶---视觉Transformer的应用

1 背景 在过去的几年&#xff0c;随着自动驾驶技术的不断发展&#xff0c;神经网络逐渐进入人们的视野。Transformer的应用也越来越广泛&#xff0c;逐步走向自动驾驶技术的前沿。笔者也在博客《人工智能---什么是Transformer?》中大概介绍了Transformer的一些内容&#xff1a…

el-image 使用静态资源,通过遍历展示多图

关键代码&#xff1a;&#xff08;通过v-for 遍历获取&#xff09; <div v-for"item in projectCase" :key"item.id" class"block" click"aa(item)" :iditem.className><el-image :srcitem.url:fit"fit":preview-…

go-kratos 学习笔记(2) 创建api

proto 声明SayHi 先删除go.mod 从新初始化一下 go mod init xgs_kratosgo mod tidy 编辑 api/helloword/v1/greeter.proto 新声明一个方法 rpc SayHi (HelloHiRequest) returns (HelloHiReply) {option (google.api.http) {post: "/hi"body: "*"};} …

【Godot4.2】GodotXML插件 - 解析和生成XML

概述 近期在研究Godot的XML和SVG解析&#xff0c;Godot提供了XMLParser类型&#xff0c;但本身只提供了低级的XML解析接口和功能&#xff0c;想要完成完整的XML文档解析和存储可能还需要在其基础上编写类或功能&#xff0c;就像我在昨天&#xff08;2024年7月20日&#xff09;…

六边形动态特效404单页HTML源码

源码介绍 动态悬浮的六边形,旁边404文字以及跳转按钮,整体看着像科技二次元画风,页面简约美观,可以做网站错误页或者丢失页面,将下面的代码放到空白的HTML里面,然后上传到服务器里面,设置好重定向即可 效果预览 完整源码 <!DOCTYPE html> <html><head…

CH04_依赖项属性

第4章&#xff1a;依赖项属性 本章目标 理解依赖项属性理解属性验证 依赖项属性 ​ 属性与事件是.NET抽象模型的核心部分。WPF使用了更高级的依赖项属性&#xff08;Dependency Property&#xff09;功能来替换原来.NET的属性&#xff0c;实现了更高效率的保存机制&#xf…

python实现责任链模式

把多个处理方法串成一个list。下一个list的节点是上一个list的属性。 每个节点都有判断是否能处理当前数据的方法。能处理&#xff0c;则直接处理&#xff0c;不能处理则调用下一个节点&#xff08;也就是当前节点的属性&#xff09;来进行处理。 Python 实现责任链模式&#…