You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何我的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依赖数组是空的,所以它只会在组件第一次渲染结束后执行一次:

  1. 第一次执行时,调用setRateData和setSymbolList,触发组件重渲染。
  2. 组件重渲染后,React检查useEffect的依赖数组(还是空的,没有变化),所以不会再次执行这个effect。
  3. 没有了重复执行的effect,自然不会反复调用setState,也就不会出现无限循环啦。

补充:什么时候才会出现无限循环?

举两个常见的场景:

  • 如果你把依赖数组写成[rateData],同时在effect里调用setRateData,那么每次rateData更新,effect都会重新执行,又再次更新rateData,就会陷入循环。
  • 如果你完全省略依赖数组,effect会在每次渲染后都执行,里面的setState触发渲染,渲染完又执行effect,也会无限循环。

另外提个小细节:你代码里的console.log(symbolList)会打印空数组,因为React的setState是异步更新状态的,你调用setSymbolList后,当前渲染周期里的symbolList还没更新,要等到下一次渲染才会变成新值哦~

内容的提问来源于stack exchange,提问作者Adam Lau

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 10:49:08