vue3中watch和watchEffect用法与区别

vue3中watch和watchEffect用法与区别

两个都是vue3中的监听器,监听数据时使用

watch

基本用法

当我们需要在数据变化时执行一些"副作用":如更改 DOM、执行异步操作,我们可以使用 watch 函数。 watch默认初始不执行 ,需要修改immediate为true,来配置。该函数接收三个属性,监听数据源、回调函数、配置项

ini 复制代码
let num1 = ref(1)
let num2 = ref(2)
let sum = computed(()=>num1+num2)
let obj = reactive({name:'zy',age:"20",info:{job:'web'}})

监听数据源

接收的参数可以为 1.ref声明

javascript 复制代码
watch(num,(newVal)=>{
	console.log(num,newVal)
})

2.reavite声明 监听obj 不能监听obj.name

javascript 复制代码
watch(obj,(newVal,oldVal)=>{
//任一属性更改触发
	console.log(oldVal,newVal)
	// 注意:`newVal` 此处和 `oldVal` 是相等的
})

3.一个getter函数的值

javascript 复制代码
// getter 函数
watch(
  () => num1.value + num2.value,
  (sum) => {
    console.log(`sum of num1 + num2 is: ${sum}`)
  }
)

4.computed的值

javascript 复制代码
// 计算属性
watch(sum, (newValue) => {
  console.log(`sum is ${newValue}`)
})

5.以上类型值得集合

javascript 复制代码
/ 以上类型的值组成的数组
watch([num1, () => num2.value], ([newX, newY]) => {
  console.log(`num1 is ${newX} and num2 is ${newY}`)
})

注意

传入getter函数时只有在对象被替换时才会触发:

php 复制代码
const obj = reactive({
  someString: 'hello',
  someObject: { count: 0 }
})

watch(
  () => obj.someObject,
  () => {
    // 仅当 obj.someObject 被替换时触发
  }
)

当然,你也可以显式地加上 deep 选项,强制转成深层侦听器:

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

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

javascript 复制代码
watch(
  () => _.cloneDeep(obj.someObject),
  (newValue, oldValue) => {
    // 此时 `newValue` 此处和 `oldValue` 是不相等的
    console.log('deep', newValue.count, oldValue.count)
  },
  { deep: true }
)

	obj.someObject.count++ // deep 1 0

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

回调函数

数据发生变化时执行回调函数。 回调函数中可以接收三个参数:新值、旧值、清除副作用的回调函数,该回调函数会在副作用下一次执行前调用,可以用来清除无效的副作用,如等待中的异步请求:

scss 复制代码
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()
})

watch 有返回值,返回值是一个用来停止该副作用的函数

scss 复制代码
const unwatch = watch(() => {})
// 当该侦听器不再需要时调用
unwatch()

配置选项

第三个参数是一个可选的对象,支持以下选项: immediate :在侦听器创建时立即触发回调。 deep :深度遍历,以便在深层级变更时触发回调。 flush :回调函数的触发时机。pre:默认,dom 更新前调用,post: dom 更新后调用,sync 同步调用。 onTrack / onTrigger:用于调试的钩子。在依赖收集和回调函数触发时被调用。

watchEffect

基本用法

watch每次初始化会加载一次,不用指定监听源,自动收集依赖,只要在回调中引用到了响应式的属性,只要这些属性发生改变,回调就会执行。

接受两个参数,第一个参数是数据发生变化时执行的回调函数,用法和 watch 一样。第二个参数是一个可选的对象,支持 flush 和 onTrack / onTrigger 选项,功能和 watch 相同。

补充:如果我们想要在回调函数里面获取更新后的 DOM,我们需要给监听器多传递一个参数选项即可:flush: 'post'。,但是 Vue3 单独给 watchEffect 提供了一个更方便的方法,也可以叫做 watchEffect 的别名,代码如下:

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

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

xml 复制代码
<script setup>
import { watchEffect } from 'vue'

// 组件卸载会自动停止
watchEffect(() => {})

// 组件卸载不会停止!
setTimeout(() => {
  watchEffect(() => {})
}, 100)
</script>
scss 复制代码
const unwatch = watchEffect(() => {})
// ...当该侦听器不再需要时
unwatch()

总结

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

1.watch 只追踪明确定义的数据源,不会追踪在回调中访问到的东西;默认情况下,只有在数据源发生改变时才会触发回调;watch 可以访问侦听数据的新值和旧值。

2.watchEffect 会初始化执行一次,在副作用发生期间追踪依赖,自动分析出侦听数据源;watchEffect 无法访问侦听数据的新值和旧值。 简单一句话,watch 功能更加强大,而 watchEffect 在某些场景下更加简洁。

相关推荐
计算机魔术师7 小时前
OpenAI 发布 GPT-6 Astra:多项基准刷新纪录, cybersecurity 能力达 Critical 阈值
前端
xy34537 小时前
Axure9.0中继器遮罩实现方法
前端·ui·html·axure·原型·产品设计
风骏时光牛马7 小时前
智能任务自动化协同AI工作流
前端
IT_陈寒7 小时前
Python的多线程居然是个假把式?搞清GIL让我少熬三天夜
前端·人工智能·后端
宿6747 小时前
vue3-config
前端·javascript·vue.js
明月_清风7 小时前
位图与布隆过滤器:海量数据下的"存在性判断"艺术
前端·后端·算法
明月_清风8 小时前
Hash 表从入门到精通:Go 实战与工程细节
前端·后端·算法
非凡ghost9 小时前
AI修图不“造假“,摄影师的出片效率加速器
服务器·前端·人工智能·电脑
2601_951615209 小时前
网页设计模板源码 web前端模板网页源码下载
前端
mmsx9 小时前
osmdroid 地图实战 03|地图的"分层世界":离线方案、图层模型与 Overlay 体系
android·前端