javascript - 为什么我可以在设置状态之前访问嵌套对象,但之后却不能?
问题描述
我正在使用 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>
)
name 和 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 信息创建单独的状态变量,而不是将其存储在一个大对象中以便稍后取出?
谢谢!
解决方案
好的,所以错误的原因是您试图在加载信息之前呈现信息,因为口袋妖怪信息是从 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>
)
当然要确保对象路径都是正确的