深入理解 useEffect(适用于 React 与 Next.js)——新手指南

Wayne
作者 Wayne ·

如果你刚开始学习 React 或 Next.js,你很可能最先接触到的 Hook 就是 useEffect。它一开始看起来有些神秘,但别担心——这篇指南会用清晰的方式一步一步讲透。

什么是 useEffect?

在 React 中,useEffect 是一个用于处理组件副作用(side effects)的 Hook。

所谓“副作用”,是指发生在 UI 渲染流程之外的行为。例如:

  • 从 API 获取数据
  • 监听用户事件(如滚动、窗口大小变化)
  • 启动或清理定时器
  • 与 localStorage 或其它浏览器 API 交互

一句话概括:useEffect 允许你在组件渲染之后执行代码。

基础示例

import { useEffect, useState } from "react";

export default function MyComponent() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log("Component rendered!");
  });

  return (
    <div>
      <p>你点击了 {count} 次</p>
      <button onClick={() => setCount(count + 1)}>点我</button>
    </div>
  );
}

这里发生了什么?

  • 组件首次渲染时,会打印 "Component rendered!"。
  • 每当 count 发生变化,组件会重新渲染——effect 也会再次运行。

依赖项数组(Dependency Array)

useEffect 接受第二个参数——依赖项数组,用来控制 effect 的触发时机。

useEffect(() => {
  console.log("Runs only when `count` changes");
}, [count]);
  • [] → 只在首次挂载时运行(适合初始化逻辑)。
  • [count] → 当 count 变化时运行。
  • 省略数组 → 每次渲染后都运行(除非必要,不推荐)。

清理副作用(Cleanup)

有些 effect 需要在适当时机进行清理,比如事件监听或定时器。 你可以在 useEffect 内返回一个函数,用于清理资源。

useEffect(() => {
  const timer = setInterval(() => {
    console.log("Tick...");
  }, 1000);

  // Cleanup when component unmounts or before running again
  return () => {
    clearInterval(timer);
    console.log("Timer cleared!");
  };
}, []);

Next.js 中的注意事项

由于 Next.js 支持服务端渲染(SSR),需要注意:

  • useEffect 只会在客户端运行,不会在服务端执行。
  • 因此你可以在 useEffect 中安全使用仅浏览器可用的特性(如 window、localStorage)。

核心要点回顾

  • useEffect:在渲染后执行副作用。
  • 依赖项数组决定 effect 何时运行。
  • 返回一个函数用于清理(如定时器、事件监听)。
  • 在 Next.js 中,它仅在浏览器端运行,不会在服务端运行。