TypeError:无法读取未定义的属性“rocket_name”——即使它已定义
Posted
技术标签:
【中文标题】TypeError:无法读取未定义的属性“rocket_name”——即使它已定义【英文标题】:TypeError: Cannot read property 'rocket_name' of undefined -- Even though it is defined 【发布时间】:2020-05-31 11:25:27 【问题描述】:我正在使用SpaceX
API 来构建个人项目。我正在使用 React Router 来动态加载组件,而不是刷新整个网站。
这是我试图输出一些数据的LaunchDetails
组件:
import React, Component from 'react'
class LaunchDetail extends Component
state =
launch: []
async componentDidMount ()
try
const res = await fetch(`https://api.spacexdata.com/v3/launches/$this.props.match.params.flight_number`)
const data = await res.json()
this.setState(
launch: data,
rocket: data.rocket
)
catch (e)
console.log(e)
render ()
const launch, rocket = this.state
console.log(rocket)
return (
<div>
<div>
<h1>launch.mission_name</h1>
<p>SpaceX Flight Number: launch.flight_number</p>
<p>Launched: launch.launch_year</p>
<p>Rocket: rocket.rocket_name, rocket.rocket_type</p>
</div>
</div>
)
export default LaunchDetail
像launch.mission_name
这样深一层的数据正在正确显示...但是,当我尝试向下一层,比如rocket.rocket_name (eg: launch.rocket.rocket_name)
时,它会引发上述错误。
奇怪的是,这在另一个组件中有效,但它使用了不同的端点(所有数据),我正在通过它进行映射。不知道我在这个组件中调用数据的方式是否应该归咎于......
有人知道为什么会发生这种情况吗?
编辑:收到一些 cmets 后,我已将代码更新为更简单,但错误仍然存在:
import React, Component from 'react'
class LaunchDetail extends Component
state =
launch: []
async componentDidMount ()
try
const res = await fetch(`https://api.spacexdata.com/v3/launches/$this.props.match.params.flight_number`)
const data = await res.json()
this.setState(
launch: data
)
catch (e)
console.log(e)
render ()
const launch = this.state
return (
<div>
<div>
<h1>launch.mission_name</h1>
<p>SpaceX Flight Number: launch.flight_number</p>
<p>Launched: launch.launch_year</p>
<p>Rocket: launch.rocket.rocket_name, launch.rocket_type</p>
</div>
</div>
)
export default LaunchDetail
【问题讨论】:
我很确定这不是由“3 级深度”属性引起的,但在您的渲染中更是如此:rocket.rocket_name
。火箭最初并未在状态中定义,因此 this.state.rocket
将未定义,并且它的访问子属性将给出您得到的错误。您在componentDidMount
中获取数据,但该生命周期方法在第一次渲染之后被调用。所以如果你应该有一个渲染的加载状态(当数据被获取时),最好是状态的默认值
尝试在初始state = launch: []
中初始化rocket
好的,所以我在状态中添加了rocket
,仍然是同样的错误。我现在已将其删除,以便它现在引用 launch.rocket.rocket_name
并且错误仍然存在......
【参考方案1】:
从here 你可以发现 react 生命周期方法的顺序如下。
componentWillMount --> 渲染 --> componentDidMount
你已经用
初始化了状态state =
launch: []
所以在第一次渲染时,state.rocket
将是未定义的。
要解决此问题,请初始化 state.rocket 或将 componentDidMount
更改为 componentWillMount
前者是首选。
注意 componentWillMount
在版本 17 中已弃用。
在 OP 的编辑之后。您仍在将启动初始化为 []
在第一次渲染时,launch.rocket
将是未定义的。因此launch.rocket.rocket_name
会抛出错误。
要么初始化 launch
以拥有 rocket
字段。或者做类似的事情
(launch.rocket || ).rocket_name
,或在访问 rocket_name
之前检查 rocket
是否已定义的其他内容。
【讨论】:
谢谢,这是我的代码:launch: rocket: []
希望您能看到这一点,为什么我需要初始化 rocket
的状态以及此组件中的任何其他数据,而不是在我调用所有数据的其他组件中?我希望这是有道理的......
你需要在这个组件中初始化火箭状态的唯一原因是为了第一次渲染。正如您所假设的那样,总会有一个带有 rocket
属性的 launch
对象,该属性具有 rocket_name
字段。
就我个人而言,我不会在这个组件中初始化火箭,并在我的渲染中使用类似(launch.rocket || ).rocket_name
的东西。这样,如果rocket
未定义,访问rocket_name
将不会引发错误,它只会呈现任何内容。在rocket
通过componentDidMount
初始化后,它将呈现新的rocket_name
以上是关于TypeError:无法读取未定义的属性“rocket_name”——即使它已定义的主要内容,如果未能解决你的问题,请参考以下文章