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”——即使它已定义的主要内容,如果未能解决你的问题,请参考以下文章

TypeError:无法读取未定义的属性“findAll”(expressjs)

TypeError:无法读取未定义的属性(读取“问题”)

TypeError:无法读取未定义的属性“babel”

TypeError:无法读取未定义的属性(读取“匹配”):

TypeError:无法读取未定义的属性“存在”

TypeError:无法在 gitlab 中读取未定义的属性(读取“读取”)