搞懂面试常考的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应用的交互性和响应性,为用户提供更加流畅和智能的体验。

相关推荐
祈澈菇凉23 分钟前
如何结合使用thread-loader和cache-loader以获得最佳效果?
前端
垣宇26 分钟前
Vite 和 Webpack 的区别和选择
前端·webpack·node.js
java1234_小锋29 分钟前
一周学会Flask3 Python Web开发-客户端状态信息Cookie以及加密
前端·python·flask·flask3
化作繁星33 分钟前
如何在 React 中测试高阶组件?
前端·javascript·react.js
初遇你时动了情36 分钟前
react module.scss 避免全局冲突类似vue中scoped
vue.js·react.js·scss
Au_ust40 分钟前
千峰React:函数组件使用(2)
前端·javascript·react.js
爱吃南瓜的北瓜1 小时前
npm install 卡在“sill idealTree buildDeps“
前端·npm·node.js
TTc_1 小时前
记录首次安装远古时代所需的运行环境成功npm install --save-dev node-sass
前端·npm·sass
翻滚吧键盘1 小时前
npm使用了代理,但是代理软件已经关闭导致创建失败
前端·npm·node.js
烂蜻蜓1 小时前
Uniapp 设计思路全分享
前端·css·vue.js·uni-app·html