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

ReactJS页面刷新时PokemonCard组件API数据为何变为初始空对象?

React State与useEffect问题:刷新后状态回退至初始值

问题描述

在PokemonCard组件的pokemonTypes方法中,首次加载页面时控制台能打印更新后的pokemonData状态;但刷新页面后,控制台打印的却是初始状态的空对象。

相关代码

App.js

import './App.css';
import { useState, useEffect } from 'react';
import PokemonCard from './components/PokemonCard';

const interval = {
  limit: 25
}

const App = (props) => {
  const { pokedex, } = props
  const [pokemonList, setPokemonList] = useState([])

  useEffect(() => {
    const getPokemonListData = async () => {
      let pokemon = await pokedex.getPokemonsList(interval)
      setPokemonList(pokemon.results)
    }

    getPokemonListData()

  }, [])

  return (
    <div className="App">
      <h1>Pokedecs</h1>

        <div className="container">
          {
            pokemonList?.map(poke => {
              return <PokemonCard key={poke.name} pokedex={pokedex} pokemonName={poke.name} />
            })
          }
        </div>

    </div>
  );
}

export default App;

PokemonCard.js

import { useEffect, useState } from "react"
import PokemonTypePill from "./PokemonTypePill"
import '../App.css';

const PokemonCard = (props) => {
    let styles = {
        card: {
            backgroundColor: "#fff",
            height: "200px",
            width: "150px",
            boxShadow: '1px 2px 5px #000000',
            margin: "15px",
            textAlign: "center",
            borderRadius: "12px",
            fontWeight: "bold",
            transition: "transform .2s"
        }
    }

    const {pokemonName, pokedex, } = props
    const [pokemonData, setPokemonData] = useState({})

    const getPokemonData = async () => {
        let pokemon = await pokedex.getPokemonByName(pokemonName)
        setPokemonData(pokemon)
    }

    const pokemonTypes = () => {
        console.log(pokemonData) //this always uses the initial state "{}"
    }

    useEffect(() => {
        getPokemonData()
        pokemonTypes()
    }, [setPokemonData])

    return (
        <div className="card" style={styles.card}>
            <img src={pokemonData.sprites && pokemonData.sprites?.front_default} />
            <p>#{pokemonData.id} {pokemonName.charAt(0).toUpperCase() + pokemonName.slice(1)}</p>
            <div style={{width: "inherit", display: "flex", alignContent: "center", justifyContent: "center"}}>
                {
                    pokemonData.types?.map((pokemonType) => {
                        return (
                            <PokemonTypePill key={pokemonType.type.name} typeName={pokemonType.type.name} />
                        )
                    })
                }
            </div>
        </div>

    )
}

export default PokemonCard

问题原因

  1. useEffect依赖项错误:当前useEffect的依赖是setPokemonData,但setPokemonData是React内部稳定的函数,不会触发副作用重新执行。同时,getPokemonData是异步函数,调用后立刻执行pokemonTypes,此时setPokemonData还未完成状态更新,pokemonData仍为初始空对象。首次加载的偶然正常是React渲染时序的巧合,不具备稳定性。
  2. 未监听状态变化:pokemonTypes依赖pokemonData的更新,但没有在状态变化时触发执行。

解决方案

步骤1:修正useEffect依赖项

将请求数据的useEffect依赖项改为pokemonName和pokedex,确保当props变化时重新请求数据,移除不必要的setPokemonData依赖。

步骤2:监听pokemonData状态变化

新增一个useEffect,专门监听pokemonData的变化,当状态更新后再执行pokemonTypes。

修改后的PokemonCard核心代码

// ...其他代码不变

const getPokemonData = async () => {
    let pokemon = await pokedex.getPokemonByName(pokemonName)
    setPokemonData(pokemon)
}

const pokemonTypes = () => {
    console.log(pokemonData)
}

// 负责请求数据的副作用
useEffect(() => {
    getPokemonData()
}, [pokemonName, pokedex]) // 依赖props,确保props变化时重新请求

// 监听pokemonData变化,状态更新后执行pokemonTypes
useEffect(() => {
    if (Object.keys(pokemonData).length > 0) { // 避免初始空对象时执行
        pokemonTypes()
    }
}, [pokemonData])

// ...其他代码不变

补充说明

  • React的状态更新是异步的,不能在调用setState后立刻获取更新后的状态值。
  • 副作用的依赖项必须包含所有在副作用中使用的外部变量,否则会导致闭包问题,拿到旧的状态或props值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 12:54:55