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

React子组件中fetch数据为何显示undefined?

问题分析与解决方案

核心问题

问题根源在于父组件将JSX元素直接存入了state。点击按钮调用setDiv时,传递给Race组件的fetchData是当时的状态快照,后续父组件fetchData更新后,存在state里的JSX不会自动重新渲染,导致子组件始终拿到初始状态的fetchData。另外,父、子组件的useEffect都缺少依赖数组,会引发无限重复执行fetch请求的潜在问题。


解决方案步骤

1. 移除JSX存state的写法,改用条件渲染

不要把JSX存在state里,而是在组件渲染逻辑中直接根据状态判断要显示的内容。这样每次父组件状态更新(比如fetchData变化),都会生成最新的JSX,传递最新的props给子组件。

修改后的父组件代码:

export default function CharCreator () {
    const [fetchData, setFetchData] = useState(...someObj)
    // 用状态标记当前视图类型,而非存储JSX
    const [currentView, setCurrentView] = useState('initial')

    // 修复useEffect,添加空依赖数组,仅组件挂载时执行一次fetch
    useEffect(() => {
        const fetchCall = async () => {
            try{
                const res = await fetch('https://www.dnd5eapi.co/api/races')
                const data = await res.json()

                setFetchData(prevData => ({
                    ...prevData,
                    race_list:data.results
                }))
            }catch(err){
                console.error('Error fetching data: ', err)
            }
        }
        fetchCall()
    }, [])

    const handleNewChar = (e, newView) => {
        e.preventDefault()
        setCurrentView(newView)
    }

    // 根据currentView渲染对应内容
    const renderCurrentView = () => {
        if(currentView === 'class/race'){
            return (
                <div id='race_class'>
                    <div id='race'>
                        <Race functions={{
                            setFetchData:setFetchData,
                            raceFetch: raceFetch,
                            fetchData:fetchData
                        }} />
                    </div>
                </div>
            )
        }
        // 默认显示初始视图
        return (
            <div>
                <button onClick={(e) => {handleNewChar(e, 'class/race')}}>Create Character</button>
            </div>
        )
    }

    return(
        <div id='outerParent'>
            <form>
                {renderCurrentView()}
                <p>
                    <button onClick={logs}>fetchData</button>
                </p>
            </form>
        </div>
    )
}

2. 移除子组件中重复的fetch请求

父组件已负责获取race_list数据,子组件直接使用父组件传递的fetchData即可,同时优化子组件渲染逻辑:

修改后的子组件代码:

export default function Race({functions}) {
    const {fetchData, raceFetch, setFetchData} = functions
    const [spawn, setSpawn] = useState(0) // 补充缺失的spawn状态

    const isHidden = fetchData?.race?.name ? '' : 'none'

    // 移除重复的fetch请求

    // 直接在render中渲染select,无需存入state
    const renderRaceSelect = () => {
        if(!fetchData?.race_list) return null
        return (
            <p> 
                <select onChange={verifyInput} id='raceSet' defaultValue=''>
                    <option value='' disabled >Select a Race</option>
                    {fetchData.race_list.map((race, i) => (
                        <option
                            key={i}
                            data-url={race.url}
                            value={race.name}>
                            {race.name}
                        </option>
                    ))}
                </select>
            </p>
        )
    }

    const verifyInput = (e) => {
        const input = e.target.value
        const selected = e.target.options[e.target.selectedIndex]
        const url = selected.getAttribute('data-url')
        
        raceFetch(url)
        setSpawn(prevSpawn => prevSpawn + 1)
    }

    return(
        <div>
            <div>
                <h2>Race</h2>
            </div>

            {renderRaceSelect()}
            
            <div>
                {spawn > 0 ? 
                    <div id='raceInfo'>
                        <RaceInfo functions={{
                            fetchData:fetchData,
                            setFetchData:setFetchData
                        }} />
                    </div>
                :''}
            </div>
        </div>
    )
}

关键说明

  • 不要把JSX存在state中:React的state应存储数据而非UI元素,直接在渲染逻辑中生成JSX,才能保证状态更新时渲染最新内容。
  • useEffect必须加依赖数组:空依赖数组确保fetch仅在组件挂载时执行一次,避免无限循环请求。
  • 子组件依赖父组件props:父组件状态更新后,props会自动传递给子组件,子组件重新渲染即可拿到最新的fetchData。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 00:07:34