搞懂面试常考的watch和watchEffect,看这篇文章就够了

前言

笔者最近在准备面试,发现好多面试官都喜欢问vue中watchwatchEffect的区别,正好最近也在写vue相关的文章,于是乎准备用这篇文章彻底讲清watchwatchEffect及它们的区别。

watch的用法

watch在官方文档的解释如下:侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数。 在我看来他的作用无非是:监视数据的变化。它只能监视以下四种数据:

1.ref定义的数据

2.reactive定义的数据

3.函数返回一个值(getter函数)

4.一个包含上述内的数组

现在让我来一一介绍这几种用法

监视ref定义的数据

基本类型数据

我们知道,ref可以定义基本类型数据和对象类型数据,那显而易见watch也能监听这两种事件,先来看监视ref定义的基本类型数据,直接写数据名即可,其本质上监视的是value的变化。

代码示例:

xml 复制代码
<template>
  <div class="person">
    <h2>当前求和为:{{ sum }}</h2>
    <button @click = changeSum>点我 sum +1</button>
  </div>
</template>

<script lang="ts" setup >
import { ref,watch } from 'vue'
  let sum = ref(0)
  function changeSum() {
    sum.value+=1
  }
  const stopWatch = watch(sum, (newValue, oldValue) => {
    console.log(`sum 的值从 ${oldValue} 变为 ${newValue}`);
    if (newValue > 10) {
      stopWatch(); // 停止监听
    }
  });
</script>
对象类型数据

要监听ref定义的对象类型数据也是直接写数据名就行了,不过这和监视基本类型数据不同的是,这个监视的是对象的地址值,如果想监视对象内部的数据,要手动开启深度监视。 注意:

  • 如果修改的是ref定义的对象中的属性,newValueoldValue都是新值,因为它们是同一个对象。
  • 如果修改的是ref定义的对象,newValue是新值,oldValue是旧值,因为它们已经不是同一个对象了 代码示例:
xml 复制代码
<template>
  <div class="person">
    <h2>姓名: {{ person.name }}</h2>
    <h2>姓名: {{ person.age }}</h2>
    <button @click="changeName">修改名字</button>
    <button @click="changeAge">修改年龄</button>
    <button @click="changePerson">修改人</button>
  </div>
</template>

<script lang="ts" setup >
import { ref,watch } from 'vue'
let person = ref({
  name: '张三',
  age: 18
})
let changeName = () => {
  person.value.name = '李四'
}
let changeAge = () => {
  person.value.age += 1
}
let changePerson = () => {
  person.value = {
    name: '李四',
    age: 20
  }
}
watch(person,(newValue,oldValue)=>{
  console.log(newValue,oldValue)
},{deep:true})

可以看到当单独修改姓名或年龄时控制台上oldValuenewValue一直都是相等的,只有修改人的时候才会二者才会出现不一样。

监视reactive定义的数据

当监视reactive定义的对象类型数据时,是默认开启了深度监视的 代码示例:

xml 复制代码
<template>
  <div class="person">
    <h2>姓名: {{ person.name }}</h2>
    <h2>年龄: {{ person.age }}</h2>
    <button @click="changeName">修改名字</button>
    <button @click="changeAge">修改年龄</button>
    <button @click="changePerson">修改人</button>
    <h2>测试数据:{{obj.a.b.c}}</h2>
    <button @click = "test">修改obj.a.b.c</button>
  </div>
</template>

<script lang="ts" setup >
import { reactive, watch } from 'vue'
let person = reactive({
  name: '张三',
  age: 18
})
let obj = reactive({
  a:{
    b:{
      c:1
    }
  }
})
let changeName = () => {
  person.name = '李四'
}
let changeAge = () => {
  person.age += 1
}
let changePerson = () => {
  Object.assign(person,{
    name:'李四',
    age:50
  })
}

let test = () => {
  obj.a.b.c = 2
}
watch(person,(newValue,oldValue)=>{
  console.log(newValue,oldValue)
},)
watch(obj,(newValue,oldValue)=>{
  console.log(newValue,oldValue)
},)

watchEffect用法

再来看看watchEffect的用法,官网中是这样介绍的:立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行该函数。 简单来说就是watchEffect不用明确指出监视的数据,函数中用到哪些属性,那就直接监视这些属性就行了

代码示例:

xml 复制代码
<template>
  <div class="smart-home">
    <h5>需求:当房间亮度低于30%或当前时间为晚上8点,则自动开启灯光</h5>
    <h5>当前亮度:{{ brightness }}%</h5>
    <h5>当前时间:{{ currentTime }}</h5>
    <button @click="increaseBrightness">增加亮度(5%)</button>
    <button @click="decreaseBrightness">降低亮度(5%)</button>
    <button @click="advanceTime">增加一小时</button>
  </div>
</template>

<script lang="ts" setup name="SmartHome">
import { ref, watch, watchEffect,computed } from 'vue';

let brightness = ref(40); 
let hour = ref(19); 

const currentTime = computed(() => `${hour.value}:00`);

function increaseBrightness() {
  brightness.value += 5;
}
function decreaseBrightness() {
  brightness.value -= 5;
}
function advanceTime() {
  hour.value += 1;
}
// 使用watch实现,需要明确的指出要监视brightness和hour
watch([brightness, hour], (values) => {
  const [newBrightness, newHour] = values;
  if (newBrightness <= 30 || newHour === 20) {
    console.log('自动开启灯光');
  }
});
// 使用watchEffect实现就不用
const stopWatch = watchEffect(() => {
  if (brightness.value <= 30 || hour.value === 20) {
    console.log(`当前亮度: ${brightness.value}%`);
    console.log('自动开启灯光');
  }
  if (brightness.value >= 50 || hour.value > 22) {
    console.log('环境已恢复正常,停止监视');
    stopWatch();
  }
});
</script>

二者对比

watch

  • 显式依赖:需要明确指定要监听的数据源。当这些依赖数据发生变化时,会执行相应的回调函数。

  • 获取原值 :在监视由 ref 定义的响应式数据时,可以访问到变化前的原始值。

  • 详细配置:不仅需要指定要监视的具体属性,还需定义相应的回调函数来处理数据变化。

watchEffect

  • 自动依赖收集:无需手动指定监听的数据源,它会自动检测并收集在其回调函数中使用的所有响应式依赖。一旦这些依赖发生变更,回调函数将重新执行。 。
  • 仅提供新值:无法直接获取到变化前的值,只能访问到变化后的最新值。
  • 简化配置:不需要明确指出要监视哪些属性,只要在回调函数中使用了某个响应式数据,就会自动监视该数据的变化。这使得代码更加简洁和易于维护。

小结

在Vue 3中,watchwatchEffect都是用于监听响应式数据变化的强大工具,但它们各自有着不同的特点和适用场景。理解这两者的区别以及如何有效地使用它们,对于构建高效、可维护的Vue应用程序至关重要。

选择使用watch还是watchEffect,主要取决于具体的应用需求和个人偏好。如果需要对特定数据进行细致的监听并处理前后状态的变化,watch是更好的选择;而当希望快速设置响应式依赖,简化代码逻辑时,watchEffect则提供了更为便捷的方式。通过合理运用这两种监听机制,可以极大地提升Vue应用的交互性和响应性,为用户提供更加流畅和智能的体验。

相关推荐
mldong32 分钟前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排1 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60612 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角3 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!3 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰3 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi5 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen5 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马6 小时前
AI源码分析:拆解模型底层实现逻辑
前端
BillKu6 小时前
全局样式变量:CSS 自定义属性(--border-color)和SCSS 变量($border-color)的说明
javascript·css·scss