ReactJS:如何从子组件访问道具

ReactJS: how to access prop from child component

我正在学习 React.js 并且我正在尝试制作一个网站 API。

对于我的一个小部件,我想显示几个口袋妖怪及其统计信息。

为此,我有一个主要组件,它将调用 API 并填充我的状态数组,然后在地图中调用 CardPokemon 子组件以显示每个口袋妖怪。

这是我的问题,在我的 Web 控制台中,我可以看到我的不同 pokemons 统计状态数组正在填满,但在我的主要组件的渲染中,我的数组的值仍然是“未定义的”。

我试图在我的代码中实现这个问题的第一个答案:,但我仍然遇到同样的问题,我的数组的值在渲染中保持“未定义”。

我在这里放了一部分代码,如有任何帮助,我们将不胜感激。

class CardPokemon extends Component {
  render() {
    return (
      <div className="Card">
        <div className="Card__img">
          <img src={this.props.pokemonImgProp[this.props.id]} alt="" />
        </div>
         ...
      </div>
    );
  }
}

class GenerationPokemonStat extends Component {
  constructor(props) {
    super(props);
    this.state = {
      pokemonNameListAPI: [],
      pokemonImgAPI: []
      ...
    };
  }

  searchAllPokemon = () => {
    let number = 151; //for the 151 first pokemon
    Axios.get(`http://localhost:5000/getPokemonByGeneration/allPokemonGen/${number}`)
      .then(res => {
        var i;
        for (i = 0; i < number; i++) {
          let copyNameArray = this.state.pokemonNameListAPI.slice();
          copyNameArray[i] = res.data.results[i].name;
          this.setState({ pokemonNameListAPI: copyNameArray })
          
Axios.get(`http://localhost:5000/getPokemonByGeneration/one_pokemon_gen/${this.state.pokemonNameListAPI[i]}`)
            .then(response => {

              let copyImgArray = this.state.pokemonImgAPI.slice();
              copyImgArray[i] = response.data.sprites.front_default;
              this.setState({ pokemonImgAPI: copyImgArray });
      
              ...

              //everything display normally in web console here
              console.log(response);
              console.log(this.state.pokemonNameAPI[i]);
              console.log(this.state.pokemonImgAPI[i]);
            })
        }
      })
  }

  render() {
    let pokemonNameListAPI = this.state.pokemonNameListAPI;
    let pokemonImgAPI = this.state.pokemonImgAPI;

    //appears to be undefined in web console
    console.log(this.state.pokemonImgAPI[0]);

    if(!pokemonNameListAPI) {
        return null;
    }

    return (
      <>
        <div>
          <button onClick={this.searchAllPokemon}>Search Pokemon</button>
          {pokemonNameListAPI[151] === undefined ? <h1 style={{ textAlign: 'center' }}>Loading...</h1> : (
            <>
              <div className="grid-container">
                {pokemonNameListAPI.map((i) => {

                  //this console.log show me undefined for pokemonImgAPI[i]
                  console.log(pokemonImgAPI[i]);

                  return <CardPokemon
                    key={i}
                    id={i}
                    pokemonImgProp={pokemonImgAPI}
                  />
                })}
              </div>
            </>
          )}
        </div>
      </>
    );
  }
}

export default GenerationPokemonStat;

代码已编辑但仍无法运行 我已尝试实施您告诉我的内容,但仍然无法正常工作,我这样做对吗?

function CardPokemon({ pokemonStatProp }) {
  return (
    <div className="Card">
      <div className="Card__img">
        <img src={pokemonStatProp[1]} alt="" />
      </div>
      <div className="Card__name">
        {pokemonStatProp[0]}
      </div>
    </div>
  );
}

class GenerationPokemonStat extends Component {
  constructor(props) {
    super(props);
    this.state = {
      pokemonNameAPI: [],
      pokemonImgAPI: [],
      pokemonLoading: true
    };
  }

  searchAllPokemon = () => {
    this.setState({ pokemonLoading: true });
    let number = 10;
    Axios.get(`http://localhost:5000/getPokemonByGeneration/allPokemonGen/${number}`)
      .then(res => {

        let nameArray = this.state.pokemonNameListAPI.slice();
        let imgArray = this.state.pokemonImgAPI.slice();

        for (let i = 0; i < number; i++) {
          nameArray[i] = res.data.results[i].name;
          Axios.get(`http://localhost:5000/getPokemonByGeneration/one_pokemon_gen/${nameArray[i]}`)
            .then(response => {

              imgArray[i] = response.data.sprites.front_default;
            })
        }
        this.setState({ pokemonNameListAPI: nameArray });
        this.setState({ pokemonImgAPI: imgArray });
        this.setState({ pokemonLoading: false });
      })
  }

  render() {
    return (
      <>
        <div>
          <button onClick={this.searchAllPokemon}>Search Pokemon</button>
          {this.state.pokemonLoading === true ? <h1 style={{ textAlign: 'center' }}>Loading...</h1> : (
            <>
              <div className="grid-container">
                {this.state.pokemonNameListAPI.map((i) => {
                  let pokemonStat = [];
                  pokemonStat[0] = this.state.pokemonNameListAPI[i];
                  pokemonStat[1] = this.state.pokemonImgAPI[i];
                  return <CardPokemon
                    key={i}
                    pokemonStatProp={pokemonStat}
                  />
                })}
              </div>
            </>
          )}
        </div>
      </>
    );
  }
}

export default GenerationPokemonStat;

您不应在设置状态后立即尝试读取状态,因为状态更新可能会异步执行(请参阅 State Updates May Be Asynchronous)。在您的情况下,这可能意味着第二次 axios 调用未获得您期望的参数并返回空结果。

试试这个:

searchAllPokemon = () => {
    let number = 151; //for the 151 first pokemon
    Axios.get(`http://localhost:5000/getPokemonByGeneration/allPokemonGen/${number}`)
      .then(res => {
        
        // Could also use computed property name.
        var combined: {name, img}[] = [];
        for (let i = 0; i < number; i++) {
          
          combined.push({name: res.data.results[i].name});

 Axios.get(`http://localhost:5000/getPokemonByGeneration/one_pokemon_gen/${res.data.results[i].name}`)
            .then(response => {

              // Have an img for a name. 
              // Find the array item matching this name so we can 
              // set the img value. 
              // This requires you to have the pokemon name in results.
              // If using computed property we could use bracket 
              // notation here instead of find.
              let c = combined.find(f => f.name === response.data.sprites.front.name);
               c.img = response.data.sprites.front_default;
              ...

            })
        }
        
        this.setState({combinedAPI: combined})
      })
  }

此外,请记住,每当您更新状态时,React 都会检测到状态更改并导致组件刷新。您当前正在一个循环中执行两个 setState 调用。我会考虑将你的 axios 结果构造成局部变量和 setState,一次,在循环之外。