本章属于 React 教程的核心路线。建议先通读概念模型,再手写最小示例,最后用练习验证自己能否独立复现。
本章目标
本章学习 useEffect、依赖数组、清理函数、外部系统,以及用 AbortController 取消请求。
阅读本章时,请把每个 API 放回“数据如何变成界面、用户操作如何改变数据”的主线中理解。React 的学习重点不是背诵语法,而是建立可预测的渲染模型。
- 识别本章概念在真实组件中的位置
- 能写出一个最小可运行示例
- 能解释常见错误为什么发生
概念模型
Effect 用于把组件同步到 React 之外的系统,例如浏览器 API、订阅、计时器和网络连接。依赖数组描述这个同步过程依赖哪些值。
你可以把 React 程序看成一棵由组件组成的元素树。每次输入数据、状态或外部系统发生变化,React 会重新计算需要展示的 React element,再用高效的方式更新浏览器中的 DOM。
最小示例
计时器需要在卸载时清理,请求需要在参数变化或卸载时取消,避免过期结果写入状态。
import { useEffect, useState } from "react";
export function LessonTimer({ lessonId }: { lessonId: string }) {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const timer = window.setInterval(() => setSeconds((value) => value + 1), 1000);
return () => window.clearInterval(timer);
}, []);
useEffect(() => {
const controller = new AbortController();
fetch(`/api/lessons/${lessonId}`, { signal: controller.signal });
return () => controller.abort();
}, [lessonId]);
return <p>已学习 {seconds} 秒</p>;
}
type LessonNote = { title: string; done: boolean };\nconst note: LessonNote = { title: 'React 教程', done: false };
规则与陷阱
规则的价值在于让多人维护同一个项目时仍能预测行为。下面这些限制看似细碎,实际都在保护组件的输入、输出和生命周期边界。
- 不要把纯计算放进 useEffect,优先在渲染期间计算。
- 依赖数组必须包含 Effect 中读取的响应式值。
- 订阅、计时器和请求都应返回清理函数。
- 不要用空依赖数组逃避更新问题,应先确认外部系统是否真的只需连接一次。
练习
练习应当先小后大:先验证一个概念,再把它接入完整页面。不要在没有理解失败原因时复制更复杂的代码。
- 写一个每秒更新的计时器并清理 timer。
- 给 fetch 增加 AbortController。
- 删除依赖数组中的变量,观察 lint 或行为问题。