承诺一切并使用React.js正确更新状态

时间:2019-02-08 12:25:24

标签: javascript reactjs api fetch es6-promise

从API获取数据我正在获取此类数据:

0: {name: "bulbasaur", url: "https://pokeapi.co/api/v2/pokemon-species/1/"}
1: {name: "ivysaur", url: "https://pokeapi.co/api/v2/pokemon- species/2/"}
2: {name: "venusaur", url: "https://pokeapi.co/api/v2/pokemon-species/3/"}
3: {name: "charmander", url: "https://pokeapi.co/api/v2/pokemon-species/4/"}
4: {name: "charmeleon", url: "https://pokeapi.co/api/v2/pokemon-species/5/"}
5: {name: "charizard", url: "https://pokeapi.co/api/v2/pokemon-species/6/"}

为了获得更详细的信息,我需要获取每个URL。我正在尝试使用Promise.all并更新状态,但是代码不起作用:

class App extends Component {
constructor(props){
super(props);
this.state = {
  pokemons: [],
  names: [],
  isLoaded: false
};
}

componentDidMount(){
this.loadPokemons();
this.loadPokemonAdditionalInfo();
}

loadPokemons(){
fetch('https://pokeapi.co/api/v2/pokemon-species')
.then(res => res.json())
.then(json => {
  this.setState({
    isLoaded: true,
    names: json.results
  })
})
}

loadPokemonAdditionalInfo(){
Promise.all(this.state.names.map(name =>
  fetch(name.url)
  .then(results => results.forEach(result => result.json())
  .then(r => {
    this.setState({
      pokemons: [...this.state.pokemons, r]
    })
  }
))))
}

请告知我我做错了。

4 个答案:

答案 0 :(得分:1)

您的问题是,在安装组件后,您将同时调用loadPokemons和loadPokemonAdditionalInfo。您需要等到获取了神奇宝贝的名字,然后才能获取它们的其他信息。

this.loadPokemonAdditionalInfo()应该从

之类的setState回调中调用
this.setState({
   isLoaded: true,
    names: json.results
}, this.loadPokemonAdditionalInfo)

答案 1 :(得分:0)

Promise.all应该具有array或promises,所以参数应该是fetches的数组。

Promise.all(this.state.names.map(name =>
  fetch(name.url)))
  .then(results => results.forEach(result => result.json())
  .then(r => {
    this.setState({
      pokemons: [...this.state.pokemons, r]
    })
  })

答案 2 :(得分:0)

首先,当您尝试加载其他数据时,名称还没有完成。

只需使您的componentDidMount函数异步并等待每个调用(还要确保您为每个调用都返回一个诺言)。

async componentDidMount(){
  await this.loadPokemons();
  await this.loadPokemonAdditionalInfo();
}

您还返回结果的迭代,而不是每个结果json的数组。

results.forEach(result => result.json())替换为:

results.map(result => result.json())loadPokemonAdditionalInfo


const results = [{ name:'John' }, { name:'Jane' }];

console.log('forEach', results.forEach(result => result.name));
console.log('map', results.map(result => result.name));

答案 3 :(得分:0)

不能同时运行

this.loadPokemons();
this.loadPokemonAdditionalInfo();

以同步方式,setState需要一些时间来更改状态。这就是为什么要对setState进行回调的原因。

以下应该有效:

loadPokemons(){
  fetch('https://pokeapi.co/api/v2/pokemon-species')
    .then(res => res.json())
    .then(json => {
      this.setState({
        isLoaded: true,
        names: json.results
      }, () => {
        this.loadPokemonAdditionalInfo()
      })
    })
}

loadPokemonAdditionalInfo() {
  const { names } = this.state;
  const promises = names.map(
    name => fetch(name.url).then(response => response.json())
  )
  Promise.all(promises).then(results => {
    this.setState({
      pokemons: [...this.state.pokemons, ...results]
    })
  })
}

componentDidMount(){
  this.loadPokemons();
}