
在 react 函数组件中,将数据获取逻辑直接写在组件顶层(而非 useeffect 中)会导致每次渲染都触发请求,造成资源浪费、状态混乱甚至内存泄漏;必须用 useeffect 并正确设置依赖数组来控制执行时机。
在 react 函数组件中,将数据获取逻辑直接写在组件顶层(而非 useeffect 中)会导致每次渲染都触发请求,造成资源浪费、状态混乱甚至内存泄漏;必须用 useeffect 并正确设置依赖数组来控制执行时机。
你提供的代码看似“能运行”,实则存在严重隐患:
import { useState } from 'react';
export default function App() {
const [title, setTitle] = useState(null);
const [num, setNum] = useState(2);
// ⚠️ 危险!此处 fetch 在每次渲染时都会执行
fetch(`https://jsonplaceholder.typicode.com/todos/${num}`)
.then((response) => response.json())
.then((response) => {
const { title } = response;
setTitle(title);
});
return (
<div classname="App">
<h1>useEffect Example</h1>
{title}
<button onclick="{()"> setNum(num + 1)}>Increment</button>
</div>
);
}
这段代码的问题在于:React 组件函数本身会随状态更新而重新执行(即 re-render),每次执行都会再次调用 fetch。例如:
- 点击按钮 → setNum(num + 1) 触发重渲染 → fetch 再次发起;
- 其他父组件传入的 prop 变化、或同级组件更新导致该组件重渲染 → fetch 仍会无条件执行;
- 若 setTitle 尚未完成,而 num 已变化,还可能引发竞态问题(如旧请求覆盖新请求结果)。
✅ 正确做法是将副作用逻辑移入 useEffect,并明确声明依赖:
import { useState, useEffect } from 'react';
export default function App() {
const [title, setTitle] = useState(null);
const [num, setNum] = useState(2);
useEffect(() => {
fetch(`https://jsonplaceholder.typicode.com/todos/${num}`)
.then((response) => {
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
})
.then((data) => {
setTitle(data.title); // 注意:响应体中 title 是字符串字段
})
.catch((error) => {
console.error('Failed to fetch todo:', error);
setTitle('Error loading title');
});
}, [num]); // ✅ 仅当 num 变化时执行
return (
<div classname="App">
<h1>useEffect Example</h1>
<p>{title ?? 'Loading...'}</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/ai/1810" title="极简智能王"><img
src="https://img.php.cn/upload/ai_manual/001/503/042/69bb77d21f22a629.png" alt="极简智能王" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/ai/1810" title="极简智能王" class="overflowclass">极简智能王</a>
<p class="overflowclass">一款集合AI聊天、绘画、写作、翻译和编程等能力的综合型AI助手,帮助用户处理多种日常学习与工作任务。</p>
</div>
<a rel="nofollow" href="/ai/1810" title="极简智能王" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
<button onclick="{()"> setNum(prev => prev + 1)}>Increment</button>
</div>
);
}
? 关键要点:
- useEffect(fn, deps) 是 React 识别“副作用”的唯一标准;脱离它,React 无法控制执行时机;
- 依赖数组 [num] 告诉 React:仅当 num 值发生变化时,才重新执行该副作用;
- 必须处理错误和加载状态(如 Loading...),提升用户体验与健壮性;
- 若需清理(如取消未完成的请求),可在 useEffect 中返回清理函数(推荐搭配 AbortController 使用)。
? 进阶提示:对于更复杂的场景(如防抖搜索、多条件联动),可结合 useCallback、自定义 Hook 或 useReducer 进一步封装逻辑,但核心原则不变——所有外部交互(API 调用、定时器、订阅等)都应置于 useEffect 中,并严格管理依赖。
不使用 useEffect 不是“简化”,而是放弃 React 的渲染协调机制——这绝非小题大做,而是保障应用可维护性与稳定性的基本要求。










