在React(状态数组)中动态添加子元素

时间:2018-11-18 15:35:11

标签: javascript reactjs dynamic

我正在努力从React中的JSON数据构建一个Pokedex。我正在从我内置的jQuery中重构这个项目,所以可能是jQuery的方法使我误解了如何使用正确的React思维来解决这个问题。到目前为止,令我困扰的是如何基于我从父元素(这将是jQuery append)传递的JSON动态呈现多个子元素。

这是我的App.js代码:

class App extends Component {
  render() {
    return (
      <div className="App background">
        <div className="content">
          <Header />
          <TilesContainer pokedexName="national"/>
        </div>
      </div>
    );
  }

TilesContainer本质上接收Pokedex的名称并调用API。各个口袋妖怪的名称都存储在TilesContainer状态(this.state.pokemon)中的数组中,如下所示。

class TilesContainer extends Component {

  constructor(props){
    super(props);
    this.state = {pokemon: []};
    this.getPokemon = this.getPokemon.bind(this);
    this.tiles = this.tiles.bind(this);
  }

  getPokemon() {
    // set this.state.pokemon to the list
    let link = 'https://pokeapi.co/api/v2/pokedex/' + this.props.pokedexName + '/';
    fetch(link)
    .then(response => response.json())
    .then(myJson => {
      let list = myJson['pokemon_entries'];
      list.forEach(pokemon => {
        this.state.pokemon.push(pokemon);
      })
    })
    this.tiles();
   }

  tiles() {
    if (this.state.pokemon.length > 0) {
      return (
          this.state.pokemon.map(pokemon => {
          <Tile number={pokemon.entry_number}/>
        })
      )
    }
  }

  render(){
    this.getPokemon();
    return (
      <div id="tiles-container"
           className="tiles-container">
             <h1>TilesContainer Test</h1>
             <Tile number={1} />

      </div>
    )
  }
}

export default TilesContainer

同样,我们的想法是为Pokedex JSON中的每个Pokemon渲染一个Pokemon磁贴(目前我已将其存储在this.state.pokemon中-不确定这是否是最佳方法)。我在此处的堆栈溢出示例中找到了一个使用附加功能的示例(本例this.tiles()用于生成我认为是带有不同子元素的返回数组)。 <Tile number={1} />是有关如何调用图块的硬编码示例。

当前,在代码运行时没有动态渲染的图块出现。这是正确的方法吗?我真的很感谢任何建议。

谢谢!

2 个答案:

答案 0 :(得分:0)

因此,您是从父组件app.js传递pokedexName的,一旦获得道具,就可以在componentWillMount生命周期中调用rest api调用。

因此在渲染上,由于api调用已启动,因此不会包含任何数据,这就是为什么api调用完成后我们使用三元运算符检查数组的原因,并且我们获取了将数据设置为神奇宝贝的数据数组。

由于状态已更新,因此react将自动渲染一个re渲染,以便数据出现。

我希望以下代码能够解决此问题,请让我知道:)

// App.js
import React, { Component } from 'react';
import TilesContainer from './components/TileContainer/TilesContainer'




class App extends Component {
  render() {
    return (
      <div>
        <TilesContainer pokedexName="national" />
      </div>
    );
  }
}


export default App;




// Tiles container
import React, {Component} from 'react';
import axios from 'axios';

class TilesContainer extends Component{
    //state 
    state ={
        pokemon: []
    }


    // life cycle methods
    componentWillMount(){
        let link = 'https://pokeapi.co/api/v2/pokedex/' + this.props.pokedexName + '/';
        axios.get(link)
        .then(res => {
            this.setState({
                pokemon: res.data["pokemon_entries"]
            })
        })
    }


    render(){
        let style ={display:"inline"}
        return(
            <div>
                {
                    this.state.pokemon.length > 0 ? 
                        this.state.pokemon.map(pokemon => {
                            return(
                                <div key={pokemon.entry_number}>
                                    <p style={style}>{pokemon.entry_number}</p>
                                    <a href={pokemon.pokemon_species.url}>{pokemon.pokemon_species.name}</a>
                                </div>
                            )
                        })    
                    :
                        null
                }
            </div>
        )
    }
}

export default TilesContainer

答案 1 :(得分:0)

好像你快到了。

首先,切勿直接修改state。请改用this.setState()。 React中的状态是异步更新的。出于您的目的,您应该可以像以下所示修改getPokemon()。我也删除了this.tiles()调用,因为这是不必要的。

getPokemon() {
  // set this.state.pokemon to the list
  let link = 'https://pokeapi.co/api/v2/pokedex/' + this.props.pokedexName + '/';
  fetch(link)
  .then(response => response.json())
  .then(myJson => {
    let list = myJson['pokemon_entries'];
    this.setState({
      pokemon: list,
    });
  })
}

tiles()的较小修正:使用箭头功能并返回一行内容时,请使用括号而不是花括号。当使用花括号时,必须包含一个return语句。有括号的话就没有。

tiles() {
  if (this.state.pokemon.length > 0) {
    return (
      this.state.pokemon.map(pokemon => (
        <Tile number={pokemon.entry_number}/>
      ))
    )
  }
}

接下来,由于tiles()返回了动态磁贴组件,因此需要将其包含在render()返回的内容中。

render(){
  return (
    <div id="tiles-container"
       className="tiles-container"
    >
      <h1>TilesContainer Test</h1>
      {this.tiles()}
    </div>
  )
}

最后,我认为对this.getPokemon()的调用在构造函数中比在render()中更有意义。

顺便说一句,我认为您获取json数据并将其存储在状态中的方法很好。将来,您可能想研究Redux来管理您的状态,但是对于一个很小的应用程序来说,这可能会显得过分杀伤。