React中不使用useEffect Hook的代码可行,是否建议采用?
关于React useEffect的必要性解答
你的代码现在能“正常运行”只是表面现象,实际上存在严重问题,绝对不能省略useEffect,你忽略了React组件的渲染机制和副作用管理的核心逻辑——哪怕是小型场景,也不能这么写,具体原因如下:
不必要的重复请求:React组件函数会在每次状态更新(比如
setTitle、setNum)、父组件重渲染、props变化时重新执行。把fetch直接写在组件函数里,意味着这些场景都会触发新的网络请求——比如setTitle更新title状态时,组件会再次渲染,又会发起一次相同的请求,纯粹是资源浪费。竞态风险:如果快速点击按钮多次,多个
fetch请求会同时发出,而响应的返回顺序可能和请求顺序不一致。比如你先请求num=3,再请求num=4,但num=3的响应晚于num=4返回,最终title会被旧数据覆盖,导致显示错误。useEffect的核心作用:它的存在就是为了让你精准控制副作用(比如网络请求、DOM操作、定时器等)的执行时机。在你的场景里,你只希望当
num变化时才发起请求,所以必须把fetch放进useEffect,并将num加入依赖数组,这样只有num改变时才会执行这个副作用。
修正后的代码(加入请求取消逻辑,彻底避免竞态问题):
import { useState, useEffect } from 'react'; export default function App() { const [title, setTitle] = useState(null); const [num, setNum] = useState(2); useEffect(() => { const controller = new AbortController(); const signal = controller.signal; fetch(`https://jsonplaceholder.typicode.com/todos/${num}`, { signal }) .then((response) => response.json()) .then((response) => { setTitle(response.title); }) .catch(err => { // 忽略请求被取消的错误 if (err.name !== 'AbortError') throw err; }); // 组件卸载或num变化时,取消未完成的请求 return () => controller.abort(); }, [num]); return ( <div className="App"> <h1>useEffect Example</h1> <pre>{title}</pre> <button onClick={() => setNum(num + 1)}>Increment</button> </div> ); }
总结:不管场景大小,直接在组件函数内写副作用都是违背React设计理念的写法,会导致不可预测的行为,必须用useEffect来管理这类操作。
内容的提问来源于stack exchange,提问作者Nesh
相关产品推荐
相关产品推荐

