【问题标题】:ReactJS: how to access prop from child componentReactJS:如何从子组件访问道具
【发布时间】:2021-11-30 13:28:08
【问题描述】:

我正在学习 React.js,我正在尝试使用 pokeAPI 创建一个网站。

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

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

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

我试图在我的代码中实现这个问题的第一个答案:why react props are passed undefined to the child component?,但我仍然遇到同样的问题,我的数组的值在渲染中仍然“未定义”。

我把我的一部分代码放在这里,任何帮助将不胜感激。

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;

【问题讨论】:

    标签: javascript arrays reactjs react-props


    【解决方案1】:

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

    试试这个:

    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,一次,在循环之外。

    【讨论】:

    • 感谢您的回答,我已尝试按照您的方式实施,但我仍然遇到同样的问题,请问我的做法是否正确?我有我的新代码,但我的编辑需要被接受。感谢您的帮助
    • 检查这一行“imgArray[i] = response.data.sprites.front_default;”。
    • axios 调用默认是异步的,所以 for 循环有可能在 axios 返回结果之前完成。 “i”的值可以是任何值。名字是独一无二的吗?我将更新上面的代码以显示可能的解决方法。
    • 我从代码的开头开始使用你的方法,现在我可以传递我的道具了,非常感谢你的帮助和你的时间:)
    • @vincent - 乐于助人。请将答案标记为已接受。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-09-11
    • 2017-03-18
    • 2019-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多