一次说清Vue3中watch、watchEffect和computed的多种用法

前言:

watch、watchEffect和computed这算是vue里面响应式API的核心了,特意总结一下当写个笔记,如有那里不对或者需要补充欢迎大佬指点。

一、watch:

简单说明:侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数。但有几种使用方法,下面一一说明。

1、watch侦听一个对象里面一个属性:

直接侦听对象里面一个属性用法

scss 复制代码
const state = reactive({ count: 0 })

watch(
  () => state.count,
  (newCount, oldCount) => {
    // 执行逻辑
  }
)

2、watch侦听一个 ref:

对ref侦听时不需要.value,直接侦听即可

scss 复制代码
const count = ref(0)

watch(count, (newCount, oldCount) => {
   // 执行逻辑
})

3、watch侦听多个来源时:

回调函数接受两个数组,分别对应来源数组中的新值和旧值

ini 复制代码
const num = ref(5)
const count = ref(100)

watch([num, count], ([newNum, newCount], [oldNum, oldCount]) => {
  // 执行逻辑
})

4、watch深度侦听和立即执行等第三个可选的参数

简单说明:如果你想让回调在深层级变更时也能触发,例如对象里面的属性
例子:如果需要添加深度侦听侦听或者立即执行,直接在后面添加{ deep: true }即可。

javascript 复制代码
const state = reactive({ count: 0 })

watch(
  () => state,
  (newState, oldState) => {
    // 执行逻辑
  },
  { 
   deep: true,     // 深侦听
   immediate: true,   // 立即执行
   once: true,    // 回调函数只会运行一次 3.4+版本
  }
)

二、watchEffect:

简单说明:立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行,可传两个参数。

第一个参数:就是要运行的副作用函数;

第二个参数:是一个可选的选项,可以用来调整副作用的刷新时机或调试副作用的依赖

  • (1)设置 flush: 'post' 将会使侦听器延迟到组件渲染之后再执行

  • (2)设置 flush: 'pre' :在组件更新更新前运行,默认为'pre'

  • (3)设置 flush: 'sync':强制效果始终同步触发。然而,这是低效的,应该很少需要。

1、watchEffect常规用法:

直接使用,不需要传入任何依赖,并且进入页面立即就会执行。

scss 复制代码
const count = ref(100)
watchEffect(() =>{
  console.log(count.value)   
})

传入第二个参数改变刷新时机的使用例子

scss 复制代码
const count = ref(100)
watchEffect(
  () => {
    console.log(count.value)
  },
  {
    flush: 'post'
  }
)

2、watchEffect停止侦听器:

简单说明:当达到某个条件后不需要侦听了,那么可以用以下方法进行停止。

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

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

3、watchEffect副作用清除:

简单说明:在开发中我们需要在侦听函数中执行网络请求,但是在网络请求还没有达到的时候如果出现以下两种情况,

(1)停止了侦听器,

(2)侦听器/侦听函数被再次执行了。

那么上一次的网络请求应该被取消掉,这个时候我们就可以清除上一次的副作用;

场景一 :如下假设网络请求要3秒完成,但2秒时就调用stop()暂停了侦听,所以会执行打印我是副作用执行了

javascript 复制代码
const stop = watchEffect((onInvalidate) => {
  const timer = setTimeout(() => {
    console.log('网络请求成功~')
  }, 3000)
  console.log(num.value)

  setTimeout(() => {
    stop()
  }, 2000)

  // 当上面的请求还没执行完就stop或者重新执行,就会触发
  onInvalidate(() => {
    clearTimeout(timer)
    console.log('我是副作用执行了')
  })
})

场景二 :下面侦听打印引用了num.value, 所以收集了num.value的依赖,当num.value变化时副作用函数都会执行一次,打印出来我是副作用执行了,并且网络请求会正常请求。

javascript 复制代码
watchEffect((onInvalidate) => {
  const timer = setTimeout(() => {
    console.log('网络请求成功~')
  }, 3000)
  console.log(num.value)

  // 当上面的请求还没执行完就stop或者重新执行,就会触发
  onInvalidate(() => {
    clearTimeout(timer)
    console.log('我是副作用执行了')
  })
})

补充:

1、watchPostEffect():watchEffect() 使用 flush: 'post' 选项时的别名。

2、watchSyncEffect():watchEffect() 使用 flush: 'sync' 选项时的别名。

三、computed()计算属性

简单说明:当想要计算的属性发生变化时,就会重新触发计算,例如:购物车。

1、创建一个只读的计算属性 ref:

只要当num属性内容变化就会触发重新计算,computedNum会同步更新

xml 复制代码
<template>
  <div>
  {{ num }}    // 5
  {{ computedNum }}   // 10
  </div>
</template>

<script setup>
import { ref } from 'vue'
const num = ref(5)

const computedNum = computed(() => {
  return num.value * 2
})
</script>

2、创建一个可写的计算属性 ref:

简单说明:对计算属性读取内容或者写入数据时可以做额外逻辑处理
读取内容时:如下所有代码会取到内容是11,因为在get里面+1操作了,如果真实项目可以更多逻辑处理。

xml 复制代码
<template>
  <div>
  {{ plusOne }}    // 11
  </div>
</template>

<script setup>
import { ref } from 'vue'
const count = ref(10)
const plusOne = computed({
  get: () => count.value + 1,
  set: (val) => {
    count.value = val - 1
  }
})
</script>

对计算属性写入内容时:如下第17行,对计算属性plusOne赋值1,但打印出来会是0,因为在set里面做了减一操作

xml 复制代码
<template>
  <div>
  {{ plusOne }}    // 0
  </div>
</template>

<script setup>
import { ref } from 'vue'
const count = ref(10)
const plusOne = computed({
  get: () => count.value + 1,
  set: (val) => {
    count.value = val - 1
  }
})

plusOne.value = 1
</script>

小结:

以上总结的各种用法场景在真实项目中应该足够实用了,但是我们要分清什么场景使用watch什么场景使用computed。

我建议是:

受多个数据影响的用computed, 例如购物车功能;

一个数据会影响到其它很多数据的用watch,例如搜索数据功能。

相关推荐
小白学习日记33 分钟前
【复习】HTML常用标签<table>
前端·html
程序员大金37 分钟前
基于SpringBoot+Vue+MySQL的装修公司管理系统
vue.js·spring boot·mysql
john_hjy37 分钟前
11. 异步编程
运维·服务器·javascript
风清扬_jd1 小时前
Chromium 中JavaScript Fetch API接口c++代码实现(二)
javascript·c++·chrome
丁总学Java1 小时前
微信小程序-npm支持-如何使用npm包
前端·微信小程序·npm·node.js
yanlele1 小时前
前瞻 - 盘点 ES2025 已经定稿的语法规范
前端·javascript·代码规范
It'sMyGo1 小时前
Javascript数组研究09_Array.prototype[Symbol.unscopables]
开发语言·javascript·原型模式
懒羊羊大王呀1 小时前
CSS——属性值计算
前端·css
xgq2 小时前
使用File System Access API 直接读写本地文件
前端·javascript·面试
李是啥也不会2 小时前
数组的概念
javascript