【问题标题】:TypeError: Cannot read property 'rocket_name' of undefined -- Even though it is definedTypeError:无法读取未定义的属性“rocket_name”——即使它已定义
【发布时间】: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 并且错误仍然存​​在......

标签: reactjs api react-router


【解决方案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
猜你喜欢
  • 2021-08-05
  • 2012-11-22
  • 2021-03-11
  • 1970-01-01
  • 2020-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多