
在 react 函数组件中,将数据获取等副作用逻辑直接写在组件顶层(而非 useeffect 中)会导致每次渲染都触发请求,不仅浪费资源,还可能引发状态竞争、内存泄漏或 ui 不一致问题。
在 react 函数组件中,将数据获取等副作用逻辑直接写在组件顶层(而非 useeffect 中)会导致每次渲染都触发请求,不仅浪费资源,还可能引发状态竞争、内存泄漏或 ui 不一致问题。
React 函数组件的主体代码会在每次渲染时同步执行——包括状态更新、props 变化或父组件重渲染触发的重新挂载。你提供的示例中,fetch 调用位于组件函数体内部(即 render phase),这意味着:
- 初始渲染时执行一次;
- 点击按钮调用 setNum(num + 1) 后,组件重渲染 → fetch 再次执行;
- 若后续因其他状态(如全局 context 更新、CSS-in-JS 主题切换等)导致重渲染,fetch 仍会无条件重复发起。
这不仅造成不必要的网络请求和性能开销,更严重的是:
✅ 多个并发请求可能使 setTitle(title) 的执行顺序不可控(后发先至),导致 UI 显示旧数据;
❌ 缺乏清理机制,若组件卸载前请求尚未完成,setTitle 将尝试更新已卸载组件的状态,触发 React 警告(“Can't perform a React state update on an unmounted component”);
❌ 无法精准控制执行时机——比如仅当 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('Network response was not ok');
return response.json();
})
.then((data) => {
setTitle(data.title); // 注意:API 返回对象含 title 字段,非嵌套在 { title } 解构中(原代码存在潜在 bug)
})
.catch((error) => {
console.error('Failed to fetch todo:', error);
setTitle('Failed to load');
});
}, [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="/xiazai/shouce/1886" title="React Native For Android 源码编译 中文WORD版"><img
src="https://img.php.cn/upload/manual/000/000/007/170907841096000.png" alt="React Native For Android 源码编译 中文WORD版" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/shouce/1886" title="React Native For Android 源码编译 中文WORD版" class="overflowclass">React Native For Android 源码编译 中文WORD版</a>
<p class="overflowclass">本文档主要讲述的是React Native For Android 源码编译;希望对大家会有帮助;感兴趣的朋友可以过来看看</p>
</div>
<a rel="nofollow" href="/xiazai/shouce/1886" title="React Native For Android 源码编译 中文WORD版" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
<button onclick="{()"> setNum(prev => prev + 1)}>Increment</button>
</div>
);
}
? 关键要点总结:
- 永远不要在组件顶层执行副作用(如 fetch、addEventListener、setTimeout、修改 DOM 等);
- useEffect(fn, deps) 是 React 提供的标准化副作用管理机制,deps 数组明确约束执行条件;
- 空依赖数组 [] 表示“仅挂载时执行一次”,而 [num] 表示“仅当 num 值变化时执行”;
- 实际项目中建议添加错误处理与加载态反馈,提升健壮性与用户体验;
- 若需取消请求(如快速切换 num 导致前序请求冗余),可结合 AbortController 进一步优化。
即使逻辑看似简单,省略 useEffect 也绝非“小case 可妥协”的选择——它是 React 函数组件副作用治理的基石,也是避免隐蔽 Bug 的必要实践。










