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

React中useEffect钩子引发无限循环的原因解惑

问题分析:React组件无限重渲染的原因

核心问题拆解

你的代码陷入无限重渲染循环,根源在于useEffect依赖数组的判断逻辑和JavaScript对象的引用特性:

  1. 对象引用的不可变性
    初始状态starWarsData是一个空对象{},当fetch请求完成后,setStarWarsData(data)会将状态替换为API返回的全新对象。哪怕两次对象的键值对完全一致,在JavaScript中它们属于不同的引用地址——React对比依赖时,只会判断引用是否相同,而非内容是否一致。

  2. useEffect的触发逻辑
    你把starWarsData放进了useEffect的依赖数组。每次组件重渲染后,React会对比依赖数组的前后值:由于新的starWarsData是新引用对象,对比结果为“不相等”,因此useEffect会再次执行。

  3. 无限循环的形成
    useEffect再次执行→发起新的fetch请求→调用setStarWarsData更新状态→状态变化触发组件重渲染→依赖数组对比不相等→useEffect再次执行……循环往复,最终导致无限重渲染。

你的理解误区

你误以为“内容一致就不会触发useEffect”,但React对引用类型(对象、数组)的依赖判断是基于引用地址,而非内容深度对比。只要引用地址不同,就会被判定为依赖变化。

解决方案

这个场景下,fetch只需要在组件首次挂载时执行一次,直接将依赖数组改为空数组即可:

import React from "react"

export default function App() {
    const [starWarsData, setStarWarsData] = React.useState({})
 
    console.log(starWarsData)
    React.useEffect(function() {
        fetch("https://swapi.dev/api/people/1")
            .then(res => res.json())
            .then(data => setStarWarsData(data))
    }, []) // 空数组表示仅在组件挂载时执行一次
    
    return (
        <div>
            <pre>{JSON.stringify(starWarsData, null, 2)}</pre>
        </div>
    )
}

如果后续需要根据对象内容变化重新触发请求,可以使用自定义的深度对比Hook(如useDeepCompareEffect),或者将对象的关键属性单独放入依赖数组,但当前场景下空数组是最直接的正确方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 05:16:04