0Pricing
Frontend Academy · 课时

useEffect 基础:依赖与清理

在渲染后运行副作用,通过依赖数组控制重新运行的时机,并返回清理函数以避免内存泄漏。

useEffect 基础:依赖与清理 是 CoddyKit 上的免费 Frontend Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Frontend Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Frontend Academy 课程共包含 4 节课。

什么是 useEffect

useEffect 会在 React 完成渲染后运行副作用。副作用包括:获取数据、订阅事件、设置计时器以及与外部 API 交互。副作用会在绘制之后运行,而不是在渲染期间运行。

基本语法

useEffect(effect, deps?)。默认情况下,副作用函数会在每次渲染后运行。提供依赖数组即可控制它的运行时机。

import { useEffect } from 'react';

function Component() {
  useEffect(() => {
    console.log('Ran after every render');
  });
}

依赖数组控制副作用运行时机

空数组 []:挂载后运行一次。非空数组 [a, b]:在 a 或 b 发生变化时运行。不提供数组:每次渲染后运行(这通常不是您想要的结果)。

// Run once on mount:
useEffect(() => {
  fetchInitialData();
}, []);

// Run when userId changes:
useEffect(() => {
  fetchUser(userId);
}, [userId]);

// Run after every render (usually a bug):
useEffect(() => {
  trackPageView();
});

清理函数

从 useEffect 返回一个函数来执行清理:移除事件监听器、取消订阅、清除计时器。清理函数会在下一次副作用运行前以及卸载时运行。

useEffect(() => {
  const handleResize = () => setWidth(window.innerWidth);
  window.addEventListener('resize', handleResize);

  // Cleanup: remove listener when effect re-runs or component unmounts
  return () => {
    window.removeEventListener('resize', handleResize);
  };
}, []);

依赖项中的过期闭包

副作用会捕获创建时所引用的值。如果您在副作用中读取状态或属性值,却没有将其列入依赖项,就会看到过期值。ESLint 的 exhaustive-deps 规则可以捕获此问题。

ESLint exhaustive-deps 规则

react-hooks/exhaustive-deps ESLint 规则会在副作用缺少依赖项时发出警告。遵循它的建议几乎总是正确的——过期依赖项会导致错误。

useEffect 与 useLayoutEffect

useEffect 会在浏览器绘制后触发。useLayoutEffect 会在 DOM 变更后、绘制前同步触发。请使用 useLayoutEffect 读取 DOM 尺寸,以避免视觉闪烁。

多个副作用

使用多个 useEffect 调用来分离不相关的关注点。每个副作用都可以有自己的依赖数组和清理逻辑。

// Separate effects for separate concerns:
useEffect(() => { document.title = `${count} items`; }, [count]);
useEffect(() => {
  const sub = wsClient.subscribe(onMessage);
  return () => sub.unsubscribe();
}, []);

竞态条件——ignore 标志

当副作用根据属性获取数据时,较早发出的请求可能在较晚的请求之后才完成。请使用清理标志来忽略过期响应。

useEffect(() => {
  let ignore = false;

  async function load() {
    const data = await fetchUser(userId);
    if (!ignore) setUser(data); // only update if not cleaned up
  }

  load();
  return () => { ignore = true; };
}, [userId]);

严格模式下副作用运行两次

React 18 严格模式会在开发环境中挂载、卸载再重新挂载组件,以暴露清理错误。您的副作用会运行两次——这是有意设计的,有助于发现缺少的清理逻辑。

何时不应使用 useEffect

请不要使用 useEffect 来:1)从属性推导状态(在渲染期间计算);2)在属性变化时重置状态(使用键属性);3)无条件更新状态(会导致循环)。如果不确定,请问自己:这段代码是在响应用户事件,还是在响应外部系统?

快速检查

useEffect 的清理函数什么时候运行?

回顾:useEffect

副作用会在渲染后运行。空依赖数组 = 挂载时运行一次。依赖数组 = 在特定变化时运行。返回清理函数以防止资源泄漏。使用多个副作用来分离不同的关注点。ignore 标志可以防止获取请求返回过期响应。严格模式会触发两次以测试清理逻辑。不要将 useEffect 用于派生值,或用于可以在渲染期间计算的状态。

常见问题解答

「useEffect 基础:依赖与清理」课时是免费的吗?

是的 — 「useEffect 基础:依赖与清理」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Frontend Academy 课程的其余内容,请升级到 CoddyKit PRO。 Frontend Academy 课程共包含 4 节课。

「useEffect 基础:依赖与清理」这节课中我会学到什么?

在渲染后运行副作用,通过依赖数组控制重新运行的时机,并返回清理函数以避免内存泄漏。 你通过在浏览器中直接运行的动手代码来练习 Frontend Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Frontend Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Frontend Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「useEffect 基础:依赖与清理」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Frontend Academy 课中编写并运行代码吗?

能。每节 Frontend Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. useEffect 基础:依赖与清理
  2. 组件挂载时获取数据
  3. 处理加载状态与错误状态
  4. 使用 AbortController 进行清理
← 返回 Frontend Academy