为何我的Next.js中useEffect内调用setState未触发无限重渲染循环?
为什么你的useEffect里调用setState没造成无限循环?
嘿,这个问题正好戳中了很多React开发者刚接触useEffect时的常见误解,我来帮你理清楚你的知识缺口在哪里~
核心误解:不是所有useEffect里的setState都会导致无限循环
你之前的认知偏差在于,默认认为只要在useEffect里调用setState,就会因为触发重渲染而让useEffect反复执行,但实际上,useEffect的执行时机完全由它的依赖数组决定。
依赖数组的关键作用
useEffect的第二个参数是依赖数组,React会在每次组件渲染完成后,对比依赖数组里的所有值:
- 如果依赖数组是空数组
[]:表示这个effect只在组件首次挂载完成后执行一次,后续不管组件因为什么原因重渲染,这个effect都不会再触发。 - 如果依赖数组里有值(比如
[base, rateData]):只有当数组里的某一个值发生变化时,React才会重新执行这个effect。 - 如果完全不传依赖数组:这个effect会在每次组件渲染完成后都执行,这时候如果里面调用了setState,就会触发重渲染,重渲染后又执行effect,从而导致无限循环。
结合你的代码分析
看你的代码:
const [base, setBase] = useState(DEFAULT_BASE) const [rateData, setRateData] = useState([]) const [symbolList, setSymbolList] = useState([]) // 初始时,我们希望以EUR为基准显示汇率 useEffect(async () => { const data = await calculator(FETCH_DATA, base) setRateData(data) // 创建符号列表 const symbols = [] Object.keys(data).map((c) => symbols.push(c) ) setSymbolList(symbols) console.log(symbolList) // 这里注意:打印的会是空数组,因为setState是异步的 }, []) // 重点:空依赖数组
因为你的useEffect依赖数组是空的,所以它只会在组件第一次渲染结束后执行一次:
- 第一次执行时,调用
setRateData和setSymbolList,触发组件重渲染。 - 组件重渲染后,React检查useEffect的依赖数组(还是空的,没有变化),所以不会再次执行这个effect。
- 没有了重复执行的effect,自然不会反复调用setState,也就不会出现无限循环啦。
补充:什么时候才会出现无限循环?
举两个常见的场景:
- 如果你把依赖数组写成
[rateData],同时在effect里调用setRateData,那么每次rateData更新,effect都会重新执行,又再次更新rateData,就会陷入循环。 - 如果你完全省略依赖数组,effect会在每次渲染后都执行,里面的setState触发渲染,渲染完又执行effect,也会无限循环。
另外提个小细节:你代码里的console.log(symbolList)会打印空数组,因为React的setState是异步更新状态的,你调用setSymbolList后,当前渲染周期里的symbolList还没更新,要等到下一次渲染才会变成新值哦~
内容的提问来源于stack exchange,提问作者Adam Lau
相关产品推荐
相关产品推荐

