# 1.watchEffect 自动收集依赖

App 为根组件 下面 Home 例子都被此组件引用

vue
// App.vue 
<template>
  <div>
    <home></home>
  </div>
</template>
<script>
import Home from "./Home.vue";
export default {
  components: {
    Home,
  },
};
</script>
<style scoped>
</style>
vue
// Home.vue
<template>
  <div>
    <h2>{{ name }}-{{ age }}</h2>
    <button @click="changeName">修改name</button>
    <button @click="changeAge">修改age</button>
  </div>
</template>
<script>
import { ref, watchEffect } from "vue";
export default {
  setup() {
    //watchEffect: 自动收集响应式的依赖
    const name = ref("Neko"); 
    const age = ref(16);
    const changeName = () => (name.value = "Nico");
    const changeAge = () => age.value++;
    //watchEffect 与 watch 不同,它会默认立即执行一次 类似 watch 中的 immediate: true
    watchEffect(() => {
      // 因为 watchEffect 会收集依赖
      console.log("name:", name.value, "age:", age.value);
    });
    return {
      name,
      age,
      changeName,
      changeAge,
    };
  },
};
</script>
<style scoped>
</style>

参考结果:

setup_watchEffect

# 2.watchEffect 的返回值 (function)

  1. 使用 watchEffect 的返回值做一个当 age > 20 就停止监听 的小案例
vue
// Home
<template>
  <div>
    <h2>{{ name }}-{{ age }}</h2>
    <button @click="changeName">修改name</button>
    <button @click="changeAge">修改age</button>
  </div>
</template>
<script>
import { ref, watchEffect } from "vue";
export default {
  setup() {
    //watchEffect: 自动收集响应式的依赖
    const name = ref("Neko"); 
    const age = ref(16);
    const changeName = () => (name.value = "Nico");
    const changeAge = () => {
      age.value++;
      if (age.value > 20) {
        stop(); // 条件满足停止监听
      }
    };
    //watchEffect 与 watch 不同,它会默认立即执行一次 类似 watch 中的 immediate: true
    const stop = watchEffect(() => {
      // 因为 watchEffect 会收集依赖
      console.log("name:", name.value, "age:", age.value);
    });
    console.log("watchEffect的返回值:", stop); // 看看 watchEffect 的返回值
    return {
      name,
      age,
      changeName,
      changeAge,
    };
  },
};
</script>
<style scoped>
</style>

参考结果:

setup_watchEffect

# 3.watchEffect 清除副作用

vue
// Home 
<template>
  <div>
    <h2>{{ name }}-{{ age }}</h2>
    <button @click="changeName">修改name</button>
    <button @click="changeAge">修改age</button>
  </div>
</template>
<script>
import { ref, watchEffect } from "vue";
export default {
  setup() {
    //watchEffect: 自动收集响应式的依赖
    const name = ref("Neko"); 
    const age = ref(16);
    const changeName = () => (name.value = "Nico");
    const changeAge = () => age.value++;
    //watchEffect 与 watch 不同,它会默认立即执行一次 类似 watch 中的 immediate: true
    const stop = watchEffect((onInvalidate) => {
      // 模拟网络请求
      const timer = setTimeout(() => {
        console.log("网络请求成功~");
      }, 2000);
      // 在这个函数中清除额外的副作用
      onInvalidate(() => {
        clearTimeout(timer); // 有点像 debounce, 一直点击会不断取消掉网络请求 timer
        console.log("onInvalidate");
      });
      console.log("name:", name.value, "age:", age.value);
    });
    return {
      name,
      age,
      changeName,
      changeAge,
    };
  },
};
</script>
<style scoped>
</style>

参考结果:

setup_watchEffect

# 4. 总结

  1. watchEffect 默认会执行一次
  2. watchEffect 的返回值是一个函数,因此可以在条件满足的情况下调用函数来停止监听
  3. watchEffect 的参数: effect 是函数
  4. effect 自己也有参数: onInvalidate ,也是一个函数,用于清除 effect 产生的副作用。
  5. watchEffect 可以用来发送网络请求,用 onInvalidate 来清除,效果类似 debounce
  6. watchEffect 是没有 oldValue