开发者问题收集

ReactJS 错误从 axios 调用 api 获取分配的对象

2020-02-09
56

我有以下代码:

import React, { Component } from 'react';
import axios from 'axios';

class Dashboard extends Component {
     state = {
         name : 'randomname',
         apiData: {}
};

componentDidMount() {
  axios.get('https://api_url/getdata)
    .then(res => {
        const apiData = res.data
        this.setState({apiData});
    });
}

render() {
  const { name, apiData} = this.state;

  //THIS WORKS
  var objTest = [{game_id: 2}]; //This is returned from apical
  console.log(objTest[0].game_id);

  console.log(apiData); //logs the following: [{game_id: 2}]
  console.log(apiData[0]); //logs the following: {game_id: 2}
  console.log(apiData[0].game_id); //Error occurs See error below

  return (  
    <div className="wrap">
         TESTING
    </div>
  );
}
}

export default Dashboard;

在测试并尝试使用 console.log(apiData[0].game_id); 获取 game_id 时,我收到以下错误:

TypeError: undefined is not an object (evaluating 'apiData[0].game_id')

我想知道为什么当我声明一个变量并为其分配与 api 调用返回相同的值时,这会起作用。但是当我将 api 调用分配给 apiData 时,它不起作用。它只能访问返回 {game_id:2apiData[0] ,但无法访问 apiData[0].game_id。

感谢大家的帮助!

3个回答

这里的主要问题是生命周期方法的顺序。在挂载阶段,先调用构造函数,然后调用渲染方法。ComponentDidMount 尚未调用,因此您的状态为空。记录 apiData 或 apiData[0] 时没有收到错误的原因是,它只是在初始渲染调用(挂载阶段)期间记录空数组或对象,然后在 componentDidMount(更新阶段)之后的第二次渲染期间记录实际对象。但是当您尝试调用属性 (game_id) 时,您会在挂载阶段收到错误 (undefined),因为您在空数组/对象上调用它。

解决方案是在调用父对象上的属性之前检查其是否存在,例如,使用可选链(JS2020 新未来)检查 apiData[0],只需在对象后附加“?”即可修复错误。您也可以对较旧的 JS 使用其他方法。

console.log(apiData[0]?.game_id)
Firealem Erko
2020-02-09

ComponentDidMount 在 render 方法加载后触发。这意味着 console.log(apiData[0]) 在调用 componentDidMount 方法之前首先调用默认状态。

此处的默认状态是一个空对象,而不是数组。因此 apiData 的索引 0 为空。将默认状态更改为 apiData: [{game_id: null}] 将为您提供结果,并且一旦触发 componentDidMount 并成功调用 api,状态就会改变。

然而,这不是最好的方法。它只是为了让事情变得清晰易懂。

SSK
2020-02-09

只需在状态中定义一个标志,然后检查数据是否可用,一旦获取数据,更改该标志并相应地加载组件元素。

请参阅下面的解决方案以了解您的问题陈述。

import React, { Component } from 'react';
import axios from 'axios';

class Dashboard extends Component {
     state = {
         loading:true,
         name : 'randomname',
         apiData: {}
};

componentDidMount() {
  axios.get('https://api_url/getdata').then(res => {
        this.setState({apiData:res.data, loading:false});
    });
}

render() {
  const { name, apiData, loading} = this.state;

  //THIS WORKS
  var objTest = [{game_id: 2}]; //This is returned from apical
  console.log(objTest[0].game_id);

  console.log(apiData); //logs the following: [{game_id: 2}]
  console.log(apiData[0]); //logs the following: {game_id: 2}
  console.log(apiData[0].game_id); //Error occurs See error below

  return (  
    <div className="wrap">
         {loading ? <div>Loading ...</div> : <div className="wrap">TESTING</div>}
    </div>
  );
}
}

export default Dashboard;
Rahul Huljute
2020-02-17