TypeError:无法使用React读取undefined的属性

时间:2019-04-28 05:51:21

标签: javascript ajax reactjs api

我是React的新手,并且正在使用PokeAPI做一个小应用程序。我有一个名为PokemonDetail的组件,我想在其中显示口袋妖怪的详细信息,但应用程序抛出下一个错误

  

TypeError:无法读取未定义的属性'front_default'

我的组件看起来像这样:

import React from "react";

const PokemonDetail = ({ pokemon }) => {
  return (
    <div>
      <div className="text-center">{pokemon.name}</div>
      <img src={pokemon.sprites.front_default} alt={pokemon.name} />
      {pokemon.id}
    </div>
  );
};

export default PokemonDetail;

PokemonDetail从中获取神奇宝贝道具的App组件如下所示:

import React from "react";
import PokeAPI from "../apis/PokeAPI";
import SearchBar from "./SearchBar";
import PokemonDetail from "./PokemonDetail";

class App extends React.Component {
  state = { pokemon: '' };

  onTermSubmit = async term => {
    try {
      const response = await PokeAPI.get(`pokemon/${term}`);
      this.setState({ pokemon: response.data });
      console.log(response);
    } catch (error) {
      console.log("No existe");
    }
  };

  render() {
    return (
      <div className="container">
        <div className="row mt-3">
          <div className="col">
            <SearchBar onFormSubmit={this.onTermSubmit} />
          </div>
        </div>
        <div className="row mt-3">
          <div className="col-9" />
          <div className="col-3">
            <PokemonDetail pokemon={this.state.pokemon} />
          </div>
        </div>
      </div>
    );
  }
}

export default App;

我不明白为什么它会引发此错误,因为仅将其与json的此属性和其他属性一起引发。在name属性有效的情况下,请等待直到我向其发送一些道具,这些道具与id相同,但在front_default属性(图像的网址)上则无效。

4 个答案:

答案 0 :(得分:2)

由于ajax比反应渲染慢,因此可以在获取数据之前使用加载组件。

const PokemonDetail = ({ pokemon }) => {
  if(pokemon.sprites == undefined){
      return(
        <div>
            Loading...
        </div>
      );
  }
  return (
    <div>
      <div className="text-center">{pokemon.name}</div>
      <img src={pokemon.sprites.front_default} alt={pokemon.name} />
      {pokemon.id}
    </div>
  );
};

答案 1 :(得分:1)

很可能只是AJAX问题,您的组件会在有时间完成对API的请求之前呈现。渲染图像之前,请尝试添加其他检查。

import React from "react";

const PokemonDetail = ({ pokemon }) => {
  return (
    <div>
      <div className="text-center">{pokemon.name}</div>
       {pokemon.sprites ? (
        <img src={pokemon.sprites.front_default} alt={pokemon.name} />
        ) : ( 
          null
        )
       }
      {pokemon.id}
    </div>
  );
};

export default PokemonDetail;

答案 2 :(得分:1)

@ZHAOXIANLONG为您提供了最佳解决方案(在您接收数据之前使用加载组件),但是,如果不使用加载组件,则可以使用 lodash中的 get 方法库[1],以避免可能的错误。

import React from "react";
import _ from 'lodash';

const PokemonDetail = ({ pokemon }) => {
    const front_default = _.get(pokemon, 'sprites.front_default', 'DEFAULT_VALUE');
    const name = _.get(pokemon, 'name', 'DEFAULT_VALUE');

    return (
        <div>
            <div className="text-center">{pokemon.name}</div>
            <img src={pokemon.sprites.front_default} alt={pokemon.name} />
            {pokemon.id}
        </div>
    );
};

export default PokemonDetail;

其中第三个参数('DEFAULT_VALUE')是默认值,如果lodash无法为您的查询检索值,将使用该默认值。

PS:即使您知道可以更改API服务器,我还是建议您甚至在@ZHAOXIANLONG解决方案中使用lodash。

[1] https://lodash.com/docs/4.17.11#get

答案 3 :(得分:0)

初始状态为{ pokemon: '' }pokemon是一个空字符串。 PokemonDetail指的是pokemon.sprites.front_default,但是pokemon最初是一个字符串,并且字符串没有名为sprites的字段。

如果希望口袋妖怪最终成为对象,则可以将其初始化为看起来像对象的东西:

state = { pokemon: { sprites: {front_default: '' }}};