computed、watch、watchEffect区别

computed、watch、watchEffect 区别

20240924135726

一、计算属性

computed()

计算属性,依赖其他数据,根据依赖的数据进行计算得到的结果。
特点:

  1. 接收一个 getter 函数,返回值为一个计算属性 ref;
  2. 计算属性会自动追踪响应式依赖;
  3. 计算属性会缓存,只有当依赖数据发生变化时才会重新计算;
  4. 计算属性默认是只读的,可写属性通过 gettersetter 创建;

二、侦听器

1.watch()

特点:

  1. watch 的第一个参数可以是ref(包括计算属性)reactivegetter函数(() => x.value + y.value)、多个数据源组成的数组,第二个参数是回调函数,第三个参数是配置对象;
  2. 不能直接侦听响应式对象的属性值,使用() => obj.count,代替obj.count;
  3. 回调函数可接受 3 个参数,新值、旧值,以及一个用于注册副作用清理的回调函数;
配置对象
deep
  1. 当侦听属性是一个是由 ref 处理的响应式对象的话,就需要手动开启深度侦听 deep: true,否则 watch 无法侦听到里面属性的变化;
  2. 当侦听属性是一个是由reactive处理的响应式对象的话,会强制开启深度侦听,deep配置无效(存在特殊情况),此时newValueoldValue相等(同一个对象);
  3. 特殊情况:
    监视 reactive 所定义的一个响应式数据中的对象属性,此时 deep 配置有效
    // job为对象属性
    watch(
      () => data.job,
      (newValue, oldValue) => {
        console.log('data变了', newValue, oldValue)
      },
      { deep: true }
    )
    
immediate

默认懒执行,当侦听属性发生变化时才会执行回调函数,可使用immediate: true强制立即执行;

once

使用once:true,表示只侦听一次;

flush

Vue 组件更新是异步的,当侦听属性发生变化时,就可能触发 Vue 组件的更新和侦听回调。默认情况下,侦听回调的触发会在 Vue 组件更新之前,设定flush: post,可以将侦听回调触发时机改为 Vue 组件更新之后。
值:'pre'(默认值)、'post''sync'

副作用清理

使用场景:取消过时请求(当id已经发生变化,但是请求还未结束时,取消掉之前的请求)

import { watch, onWatcherCleanup } from 'vue'

watch(id, newId => {
  const controller = new AbortController()

  fetch(`/api/${newId}`, { signal: controller.signal }).then(() => {
    // 回调逻辑
  })

  onWatcherCleanup(() => {
    // 终止过期请求
    controller.abort()
  })
})

注意:
–onWatcherCleanup 仅在 Vue 3.5+ 中支持,并且必须在 watchEffect 效果函数或 watch 回调函数的同步执行期间调用:不能在异步函数的 await 语句之后调用它;
–在3.5版本之前,使用watch回调函数的第三个参数/watchEffect回调函数的第一个参数作为副作用清理回调。此外,通过函数参数传递的 onCleanup 与侦听器实例相绑定,因此不受 onWatcherCleanup 的同步限制。

watch(id, (newId, oldId, onCleanup) => {
  // ...
  onCleanup(() => {
    // 清理逻辑
  })
})

watchEffect((onCleanup) => {
  // ...
  onCleanup(() => {
    // 清理逻辑
  })
})
返回

返回一个函数,用于停止侦听器。

const number = ref(1)

// 定时触发此方法
const upNumber = () => {
  number.value++
}

setInterval(() => {
  upNumber()
}, 1000)

const stop = watch(number, () => {
  console.log(number.value)
  // 停止侦听
  stop()
})

注意:副作用函数中使用异步语句才需要手动停止,同步情况下会随着组件销毁自动停止。

2.watchEffect()

特点:

  1. 第一个参数为回调函数,第二个为配置对象;
  2. 自动追踪响应式依赖;
  3. 非惰性侦听,且不可被更改;
  4. 回调函数只接受一个用于注册副作用清理的回调函数;
配置对象
flush

和 watch 的一样,用于控制回调时机,直接使用别名 watchPostEffect、watchSyncEffect;

import { watchSyncEffect } from 'vue'

watchSyncEffect(() => {})

Vue3 会对 watchEffect 侦听器的副作用函数响应式依赖数据作缓存处理,watchEffect 侦听器可能会同时追踪多个响应式数据,当多个响应式数据在同一时间发生变化时,内部会“稍作等待”,观察是否有其他响应式数据发生变化需要触发副作用函数,而最终的结果就是控制台只触发一次副作用函数,反映最终结果。flush: sync用于打破这一缓存等待的机制,让其真正意义上的"立即触发侦听器";

import { ref, watch, watchSyncEffect } from 'vue'

const number1 = ref(1)
const number2 = ref(10)

// 点击按钮触发此方法
const upNumber = () => {
  number1.value++
  number2.value++
}

setTimeout(() => {
  upNumber()
}, 3000)

/*
watch(
  [number1, number2],
  () => {
    console.log(number1.value)
    console.log(number2.value)
  },
  { flush: 'sync' }
)
*/

// watchSyncEffect
watchSyncEffect(() => {
  console.log(number1.value)
  console.log(number2.value)
})

上述代码中没有添加 flush: 'sync',副作用函数只触发一次,添加 flush: 'sync',副作用函数触发两次。
运行结果:
20240920092947

返回

watch
注意:watchEffect 侦听器会立即执行,可能会有如下报错:
20240924104938
解决:使用flush:post配置项

侦听器官方参考链接

https://cn.vuejs.org/guide/essentials/watchers#callback-flush-timing

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值