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 反馈 — 无需本地设置。
此课程中的所有课时
- useEffect 基础:依赖与清理
- 组件挂载时获取数据
- 处理加载状态与错误状态
- 使用 AbortController 进行清理