Vue watch watchEffect

105 阅读3分钟

Watch

watch只能监听响应式数据(ref reactive...) ,监听多个响应式数据用数组表示

第一个参数要监听的响应式数据或者一个带返回值的函数

但是如果我需要监听dataObj这个响应式对象的age属性变化,这么写能成功监听吗?

const dataObj = reactive({ age: 1 });
function add() {
  dataObj.age++;
}
watch(dataObj.age, (newVal, oldVal) => {
  console.log(newVal, oldVal, "age");
});

image.png

显然是不行的,因为watch只能监听响应式数据,dataObj.age就只是一个普通的值了

两种办法:

  • 使用toRef变成响应式数据
watch(toRef(dataObj, "age"), (newVal, oldVal) => {
  console.log(newVal, oldVal, "age");
});
  • 将它作为函数返回 ()=>dataObj.age
watch(
  () => dataObj.age,
  (newVal, oldVal) => {
    console.log(newVal, oldVal, "age");
  }
);

第二个参数是在发生变化时要调用的回调函数。

这个回调函数接受三个参数:新值、旧值,以及一个用于注册副作用清理的回调函数。

第三个可选的参数是一个配置对象

immediate

在侦听器创建时立即触发回调。第一次调用时旧值是 undefined

deep使用场景(很少使用)

如果是以ref修饰的对象,修改这个响应式对象内的属性是监听不到的,举个例子

<template>
  <div>
    <p>Original Object: {{ originalObject }}</p>
    <button @click="updateValue">Update Value</button>
  </div>
</template>

<script setup>
import { ref, watch } from 'vue';

const originalObject = ref({
    data: 'Initial Value'
});

// 不使用 deep 选项
watch(originalObject, (newVal, oldVal) => {
  console.log('Without deep:', newVal, oldVal);
});

// 使用 deep 选项
watch(originalObject, (newVal, oldVal) => {
  console.log('With deep:', newVal, oldVal);
}, { deep: true });

function updateValue() {
  originalObject.value.data = 'Updated Value';
}
</script>

image.png

点击按钮会修改originalObject里的属性,打印如下

image.png 可以看到只有deep为true时,才能监听到originalObject内属性变化

flush

首先要知道watch的回调默认在组件更新之前被调用,flush的属性默认是pre,举个例子

<template>
  <div class="main-component">
    <div ref="divRef" class="count-display">{{ count }}</div>
    <button class="add-button" @click="add">+1</button>
  </div>
</template>

<script setup>
import { ref, watch } from "vue";

const count = ref(1);
const divRef = ref(null);
function add() {
  count.value++;
}
watch(
  count,
  (newVal, oldVal) => {
    console.log(divRef.value.textContent, "age");
    console.log(oldVal, "oldVal");
    console.log(newVal, "newVal");
  },
  {
    flush: "pre",
  }
);
</script>

watch时通过ref拿到DOM的内容,点击+1,打印

image.png 可以看出拿到的DOM的内容与count的旧值相同

这是因为watch的副作用函数在组件更新前执行,这个时候拿到的数据是还没有更新的值

怎么才能拿到最新的值呢,只需要将flush属性设置为post

image.png

watchEffect

watchEffect 会自动跟踪回调中使用到的响应式数据。也就是不需要单独指定追踪哪个响应式数据,它会帮助我们智能的收集起来

与watch相同他也有flush属性,没有immediate,但是相当于immediate:true.也没有deep

watch watchEffct默认都可以进行深度监听,但是如果只需要监听其中的几个属性,使用watchEffect更好,因为它将只跟踪回调中被使用到的属性,而不是递归地跟踪所有的属性。

如果你需要新旧值,只能使用watch,但是watch监听一个响应式对象,此时新值和旧值是相同的,想拿到不同的这么写就可以了

watch(
  () => {
    return { ...dataObj };
  },//之前是直接写dataObj
  (newVal, oldVal) => {
    console.log(oldVal, "age");
    console.log(newVal, "age");
  },
);

销毁监听器

这两种都是一样的,都会返回一个函数unwatch,再次执行这个函数就会销毁监听器

const unwatch = watchEffect(() => {})
unwatch()//销毁