vue3.x之watchEffect

watchEffect

🔊 官网的介绍

为了根据响应式状态自动应用和重新应用副作用,我们可以使用watchEffect方法,它立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。也就是说,我们并不需要传入一个特定的依赖源,而且它会立即执行一遍回调函数,如果函数产生了副作用,那它就会自动追踪副作用的依赖关系,自动分析出响应源。

🔉通俗的理解

我们可以把watchEffect方法看成是一个监狱系统,我们传入的的函数就是这个监狱关押囚犯的场地。每一个进入到这个函数内部的响应式变量,就好比是一个个拥有很大能量的罪犯,从这个罪犯进入到监狱场地后,监狱系统就会自动备案及追踪这个拥有大能量罪犯的所有关系网。监狱系统一旦检测到罪犯所属关系网有一点风吹草动,监狱系统就会重新检查一下监狱整个安保体系,以防罪犯策划越狱逃跑。

🌰 举个例子

<template>
  <div>WatchEffect用法</div><br>
  <h1>姓名:{{ student.name }}</h1><br>
  <h1>年龄:{{ student.age }}</h1><br>
  <button @click="changeReactiveValue">改变信息</button>
</template>

<script setup lang="ts">
//👀:需要什么导入什么
import { reactive, watchEffect } from 'vue'
//1.定义响应式变量
const student = reactive({
  name: '铁蛋',
  age: '1'
})
//2.watchEffect侦听
watchEffect(() => {
  console.log('name:', student.name, 'age:', student.age);
})
//3.自定义函数
const changeReactiveValue = function () {
  student.name = '地瓜'
  student.age = '2'
}
</script>

效果:

语法

watchEffect(( ) => { },option?)

参数

watchEffect有两个参数:

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

第二个参数是一个可选的选项。有{flush: 'post'}{flush: 'sync'}

watchEffectflush 选项用于控制副作用函数的触发时机。flush 选项有三种可能的值:

  • flush: 'pre'  在组件更新前触发(这是默认值)。

    默认情况下,watchEffect 会在组件更新之前运行副作用函数。这意味着当响应式数据变化时,副作用会在 DOM 更新前执行。
  • flush: 'post'  在组件更新后触发。

    将 flush 设置为 'post' 可以在组件更新后触发副作用函数。这对于那些需要访问更新后的 DOM 元素的副作用来说很有用。
  • flush: 'sync'  同步地触发。

    将 flush 设置为 'sync' 可以使副作用同步触发,而不是等到下一个微任务队列。这意味着副作用会立即在响应式数据变化时执行。
import { ref, watchEffect } from 'vue';
const count = ref(0);
// 默认 flush: 'pre'
watchEffect(() => {
  console.log(`count (pre): ${count.value}`);
});

// flush: 'post'
watchEffect(() => {
  console.log(`count (post): ${count.value}`);
}, { flush: 'post' });

// flush: 'sync'
watchEffect(() => {
  console.log(`count (sync): ${count.value}`);
}, { flush: 'sync' });

count.value++;

三个 watchEffect 会在不同的时机记录 count 的值:

flush: 'pre' 会在 DOM 更新前执行。
flush: 'post' 会在 DOM 更新后执行。
flush: 'sync' 会同步执行。

作用

深度监听响应式变量ref、reactive的数据变化。

watchEffect的使用

watchEffect不需要指明侦听的对象。当侦听的回调中用到哪个属性,就侦听哪个属性。

1. watchEffect侦听ref响应式数据

🐝watchEffect侦听ref定义的一个或多个响应式数据,可以获取preValue
🐝watchEffect侦听ref定义的一个响应式数据的一个或多个属性-基本数据类型,可以获取preValue
🐝watchEffect侦听ref定义的一个响应式数据的一个或多个属性-引用数据类型,可以获取preValue。当没有具体到某个属性时,watchEffect可以侦听引用数据类型的所有属性,也能获取到preValue

 🌰示例
<!--text.vue-->
<template>
  <div>test</div>
</template>

<script setup lang='ts'>
import { ref, reactive, watchEffect, onMounted } from 'vue';
// watchEffect侦听reactive响应式数据
// 基本数据类型
const c = ref({
  name: 'c',
  prop: 'prop'
});
const d = ref({
  name: 'd',
  prop: 'prop'
});
// 引用数据类型
const c1 = ref({
  name: 'c1',
  prop: {
    name: 'c1',
    prop: 'prop'
  }
});
const d1 = ref({
  name: 'd1',
  prop: {
    name: 'd1',
    prop: 'prop'
  }
});

onMounted(() => {
  // watchEffect侦听ref数据
  c.value.name = 'c-1';
  d.value.name = 'd-1';
  c1.value.prop.name = 'c1-1';
  d1.value.prop.name = 'd1-1';
});

// 1.watchEffect侦听ref定义的一个或多个响应式数据,可以获取preValue
watchEffect(() => {
  // watchEffect不需要指明侦听的对象。当侦听的回调中用到哪个属性,就侦听哪个属性。
  console.log(c.value); // {name: 'c', prop: 'prop'} {name: 'c-1', prop: 'prop'}
  console.log(c.value.name); // c c-1
});
watchEffect(() => {
  console.log([c.value.name, d.value.name]); // ['c', 'd'] ['c-1', 'd-1']
});
// 2.watchEffect侦听ref定义的一个响应式数据的一个或多个属性-基本数据类型,可以获取preValue
watchEffect(() => {
  console.log(c.value.name); //  c c-1
});
watchEffect(() => {
  console.log([c.value.name, c.value.prop]); //  ['c', 'prop'] ['c-1', 'prop']
});
// 3.watchEffect侦听ref定义的一个响应式数据的一个或多个属性-引用数据类型,可以获取preValue
// 当具体到引用数据类型的某个属性时,能获取preValue
watchEffect(() => {
  console.log(c1.value.prop.name); // c1 c1-1
});
watchEffect(() => {
  console.log([c1.value.prop.name, c1.value.prop.prop]); // ['c1','prop'}] ['c1-1','prop']
});
// 当没有具体到某个属性时,可以侦听引用数据类型的所有属性。能获取preValue
watchEffect(() => {
  console.log(c1.value.prop); // {name: 'c1', prop: 'prop'} {name: 'c1-1', prop: 'prop'}
});
watchEffect(() => {
  console.log([c1.value.prop, d1.value.prop]); // [{name: 'c1-1', prop: 'prop'} {name: 'd1-1', prop: 'prop'}]
});
</script>

2.watchEffect侦听reactive响应式数据

🦋watchEffect侦听reactive定义的一个或多个响应式数据,可以获取preValue
🦋watchEffect侦听reactive定义的一个响应式数据的一个或多个属性-基本数据类型,可以获取preValue
🦋watchEffect侦听reactive定义的一个响应式数据的一个或多个属性-引用数据类型,可以获取preValue。当没有具体到某个属性时,watchEffect可以侦听引用数据类型的所有属性,也能获取到preValue

🌰示例

<!--text.vue-->
<template>
  <div>test</div>
</template>

<script setup lang='ts'>
import { ref, reactive, watchEffect, onMounted } from 'vue';
// watchEffect侦听reactive响应式数据
// 基本数据类型
const c = reactive({
  name: 'c',
  prop: 'prop'
});
const d = reactive({
  name: 'd',
  prop: 'prop'
});
// 引用数据类型
const c1 = reactive({
  name: 'c1',
  prop: {
    name: 'c1',
    prop: 'prop'
  }
});
const d1 = reactive({
  name: 'd1',
  prop: {
    name: 'd1',
    prop: 'prop'
  }
});

onMounted(() => {
  // watchEffect侦听reactive数据
  c.name = 'c-1';
  d.name = 'd-1';
  c1.prop.name = 'c1-1';
  d1.prop.name = 'd1-1';
});

// 1.watchEffect侦听reactive定义的一个或多个响应式数据,可以获取preValue
watchEffect(() => {
  // watchEffect不需要指明侦听的对象。当侦听的回调中用到哪个属性,就侦听哪个属性。
  console.log(c); // {name: 'c', prop: 'prop'} {name: 'c-1', prop: 'prop'}
  console.log(c.name); // c c-1
});
watchEffect(() => {
  console.log([c.name, d.name]); // ['c', 'd'] ['c-1', 'd-1']
});
// 2.watchEffect侦听reactive定义的一个响应式数据的一个或多个属性-基本数据类型,可以获取preValue
watchEffect(() => {
  console.log(c.name); //  c c-1
});
watchEffect(() => {
  console.log([c.name, c.prop]); //  ['c', 'prop'] ['c-1', 'prop']
});
// 3.watchEffect侦听reactive定义的一个响应式数据的一个或多个属性-引用数据类型,可以获取preValue
// 当具体到引用数据类型的某个属性时,能获取preValue
watchEffect(() => {
  console.log(c1.prop.name); // c1 c1-1
});
watchEffect(() => {
  console.log([c1.prop.name, c1.prop.prop]); // ['c1','prop'}] ['c1-1','prop']
});
// 当没有具体到某个属性时,它可以侦听引用数据类型的所有属性,能获取preValue
watchEffect(() => {
  console.log(c1.prop); // {name: 'c1', prop: 'prop'} {name: 'c1-1', prop: 'prop'}
});
watchEffect(() => {
  console.log([c1.prop, d1.prop]); // [{name: 'c1-1', prop: 'prop'} {name: 'd1-1', prop: 'prop'}]
});
</script>

📢 注意

1.当watchEffect侦听引用数据类型时,它可以不需要指明具体的某个属性,便能侦听到该对象的所有属性。

2.watchEffect不需要指明侦听的对象。当侦听的回调中用到哪个属性,就侦听哪个属性。

watchEffect常见用法

1. 基本用法

import { ref, watchEffect } from 'vue';
const count = ref(0);
watchEffect(() => {
  console.log(`count: ${count.value}`);
});

2. 取消副作用

import { ref, watchEffect } from 'vue';
const count = ref(0);
const stop = watchEffect(() => {
  console.log(`count: ${count.value}`);
});
// 停止副作用
stop();

3. 延迟执行{ flush: 'post' }

import { ref, watchEffect } from 'vue';
const count = ref(0);
watchEffect(() => {
  console.log(`count: ${count.value}`);
}, { flush: 'post' });

4. 自定义调度

import { ref, watchEffect } from 'vue';
const count = ref(0);
// 使用 watchEffect 自动追踪副作用
watchEffect(
  () => {
    // 这个函数在 count 发生变化时会被调用
    console.log(`count: ${count.value}`);
  },
  {
    // 配置项:onTrack 和 onTrigger 是调试钩子
    // onTrack 会在副作用追踪依赖时调用
    onTrack(e) {
      console.log('tracked', e);
    },
    // onTrigger 会在依赖变化导致副作用重新执行时调用
    onTrigger(e) {
      console.log('triggered', e);
    }
  }
);

watchwatchEffect

用了一遍watchwatchEffect之后,发现他俩主要有以下几点区别:

1.watch是惰性执行的,而watchEffect不是,不考虑watch第三个配置参数的情况下,watch在组件第一次执行的时候是不会执行的,只有在之后依赖项变化的时候再执行,而watchEffect是在程序执行到此处的时候就会立即执行,而后再响应其依赖变化执行。

2.watch需要传递监听的对象,watchEffect不需要

posted on 2024-07-12 10:43  梁飞宇  阅读(152)  评论(0)    收藏  举报