Skip to content

Vue 3 watchEffect VS React useEffect

Vue 3 watchEffect / 自动依赖追踪/立即执行/清理副作用

下面是一个使用 Vue 3 中watchEffect的简单例子,展示了如何自动追踪依赖、立即执行以及如何清理副作用。

假设我们有一个组件,它包含一个响应式的数据属性count,我们想要在count变化时做一些事情(比如打印日志),并且当组件卸载时需要清理某些资源(例如停止一个定时器)。

vue
<template>
  <div>
    <p>{{ count }}</p>
    <button @click="increment">Increment</button>
  </div>
</template>

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

export default {
  setup() {
    // 响应式状态
    const count = ref(0);

    // 使用watchEffect来自动追踪响应式状态变化
    watchEffect((onCleanup) => {
      console.log(`count is now: ${count.value}`);

      // 设置一个副作用(这里是一个定时器)
      const timer = setInterval(() => {
        console.log("这是一个定时器,但它可能需要在组件卸载时清理");
      }, 1000);

      // 提供清理函数
      onCleanup(() => {
        clearInterval(timer);
        console.log("清理定时器");
      });
    });

    // 方法来改变响应式状态
    const increment = () => {
      count.value++;
    };

    // 返回响应式状态和方法,使其在模板中可用
    return { count, increment };
  },
};
</script>

在这个例子中,watchEffect做了以下几件事情:

  1. 自动依赖追踪:它自动追踪了count这个响应式引用。当count.value改变时,watchEffect内的回调函数会被重新执行。
  2. 立即执行:一旦watchEffect被调用,它内部的回调函数立即执行一次,因此你会立即看到第一条日志打印。
  3. 清理副作用:在watchEffect的回调函数中,我们通过setInterval创建了一个定时器。同时,我们通过onCleanup函数注册了一个清理函数,该函数使用clearInterval来停止定时器。Vue 保证在需要的时候(组件卸载或响应式状态在重新执行前)调用这个清理函数,避免了潜在的内存泄露问题。

这个例子清楚地展示了watchEffect的自动依赖追踪、立即执行和清理副作用的功能,帮助你写出更简洁、更高效的 Vue 代码。

React useEffect 显式依赖列表/条件执行/清理副作用

我们通过一个 React 组件的示例来介绍useEffect的使用,包括如何显式声明依赖列表、如何根据条件执行副作用,以及如何清理副作用。

在这个例子中,我们将创建一个简单的计时器组件,它展示了如何使用useEffect来处理副作用(例如,启动和清理一个定时器),并且如何根据组件的 props 变化来重新执行副作用。

jsx
import React, { useState, useEffect } from "react";

function Timer({ start }) {
  const [count, setCount] = useState(start);

  useEffect(() => {
    // 设置定时器作为副作用
    const timer = setInterval(() => {
      setCount((prevCount) => prevCount + 1);
    }, 1000);

    // 返回一个清理函数
    return () => {
      clearInterval(timer);
      console.log("清理定时器");
    };

    // 依赖列表包含`start`,意味着当`start`变化时,副作用会重新执行
  }, [start]);

  return <div>Timer: {count}</div>;
}

export default Timer;

在上述代码中,useEffect做了以下几件事情:

  1. 显式依赖列表:通过将start传递给依赖数组,我们明确告诉 React,只有当start的值发生变化时,副作用函数才应该重新执行。这提供了对副作用执行时机的精细控制。
  2. 条件执行:由于我们在依赖列表中指定了start,这意味着副作用函数只会在start的值改变时执行,而不是在组件的每次渲染上都执行。如果我们将依赖列表留空(即[]),副作用函数仅在组件首次渲染时执行一次,并在组件卸载时执行清理。
  3. 清理副作用useEffect的回调函数返回了一个清理函数,该函数用于清理副作用(在这个例子中是停止定时器)。React 会在组件卸载时或依赖项变化前调用这个清理函数,确保不会产生内存泄漏。

这个例子展示了 React 中useEffect的基本用法,包括如何显式地管理副作用的依赖关系以及如何在组件的生命周期内正确地处理副作用。