【问题标题】:Why can I access nested objects before setting my state but not after?为什么我可以在设置状态之前访问嵌套对象,但之后却不能?
【发布时间】:2020-10-16 02:05:04
【问题描述】:

我正在使用 React 创建一个 Pokedex 应用程序,作为我刚刚学习的练习,我遇到了一些奇怪的问题。所以到目前为止的基本设置是我有一个 PokemonList 组件,它基本上是一堆单独的 PokemonPreview 组件的父组件。在创建这些 PokemonPreview 组件并从 pokeapi 获取信息时,我遇到了一些问题。这是我的 PokemonPreview 组件中的示例代码(只是相关位):

const [pokemonInfo, setPokemonInfo] = useState({})

const name = props.pokemon.name.charAt(0).toUpperCase() + props.pokemon.name.slice(1)
const url = props.pokemon.url

useEffect(() => {
    fetch(url)
        .then(res => res.json())
        .then(data => {
            console.log(data.types[0].type.name)
            setPokemonInfo(data)
        })
}, [])

return (
    <div style={{backgroundColor: '#F06430'}} className="pokemon-preview">
        <h3>{name}</h3>
        <h5>#{pokemonInfo.id}</h5>
        <h5>{pokemonInfo.types[0].type.name}</h5>
    </div>
)

名称和 url 都作为来自 PokemonList 组件的 props 传递,然后使用该 url 从 pokeapi 中提取 pokemon 的完整详细信息(例如:https://pokeapi.co/api/v2/pokemon/6)。基本上,我正在执行获取请求以获取口袋妖怪的数据,并将整个对象保存为我的状态,因此我可以根据需要从状态中的该对象中提取任何信息。我看到的奇怪的事情是我无法从我的状态对象中提取一些信息。这是存储在我的状态对象中的 JSON 示例:

{
  "abilities": [
    {
      "ability": {
        "name": "blaze",
        "url": "https://pokeapi.co/api/v2/ability/66/"
      },
      "is_hidden": false,
      "slot": 1
    },
    {
      "ability": {
        "name": "solar-power",
        "url": "https://pokeapi.co/api/v2/ability/94/"
      },
      "is_hidden": true,
      "slot": 3
    }
  ],
  "base_experience": 240,
  "types": [
    {
      "slot": 1,
      "type": {
        "name": "fire",
        "url": "https://pokeapi.co/api/v2/type/10/"
      }
    },
    {
      "slot": 2,
      "type": {
        "name": "flying",
        "url": "https://pokeapi.co/api/v2/type/3/"
      }
    }
  ],
  "weight": 905
}

我试图访问的是类型数组中的条目。正如您在我的示例代码中的控制台日志中看到的那样,我能够从请求数据中获取类型数组中的第一个条目,但是如果我尝试使用控制台日志或在我的状态中获取相同的信息组件返回,我得到一个错误:TypeError: Cannot read property '0' of undefined。返回中的 pokemonInfo.id 部分有效,但不是更多嵌套类型部分。我真的不明白为什么我能够在将其设置为我的状态之前获取此信息,但之后却不行。有谁知道为什么会这样?我是否应该为每个 pokemon 信息创建单独的状态变量,而不是将其存储在一个大对象中以便以后提取?

谢谢!

【问题讨论】:

  • 请贴出setPokemonInfo的定义。
  • 我猜你是在尝试console.log 设置后下一行的状态值。您不能这样做,因为状态更改是异步的。如果那不是您要打印的地方,请将其添加到您的问题中
  • @Jayce444 我在 useEffect 部分之后尝试了 console.log,也在我的组件的返回中。我将在其中进行编辑。
  • @Dai setPokemonInfo 是 React 用 useState 定义的

标签: javascript reactjs


【解决方案1】:

好的,所以错误的原因是您试图在加载信息之前呈现信息,因为口袋妖怪信息是从 API 获取的。你必须适应这一点。这是一个基本技术:

// Set it to null initially, since it's not defined at all
const [pokemonInfo, setPokemonInfo] = useState(null);

...

// Check if the pokemon info is null before trying to access nested data
return (
    <div style={{backgroundColor: '#F06430'}} className="pokemon-preview">
        <h3>{name}</h3>
        {
            pokemonInfo === null ?
            <h5>Loading pokemon data...</h5> :
            <>
                <h5>#{pokemonInfo.id}</h5>
                <h5>{pokemonInfo.types[0].type.name}</h5>
            </>
        }
    </div>
)

当然还要确保对象路径都正确

【讨论】:

  • 行得通!我仍然习惯于异步的东西,但这是有道理的。你会说这是处理此类事情的典型方式吗?我已经看到了一个异步函数,但还没有真正了解它是什么。将整个大型嵌套对象存储在我的状态中是一种好习惯,还是认为将各个部分保存为单独的部分或状态会更好?谢谢!
  • 是的,这是典型的方式,在获取时有一些文本或加载微调器。就如何组织状态而言,这是一个复杂的问题,但在这种情况下,如果您获得一大块数据,可以将其按原样转储到状态中。但是如果你正在构建自己的状态对象,通常越浅越好
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-02
  • 1970-01-01
  • 2012-01-22
  • 2020-07-27
  • 2016-04-29
相关资源
最近更新 更多