Обещай всем и правильно обновляй состояние используя React.js - PullRequest
0 голосов
/ 08 февраля 2019

Выборка данных из 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 голосов
/ 08 февраля 2019

Вы не можете запустить оба

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();
}
0 голосов
/ 08 февраля 2019

Ваша проблема в том, что вы вызываете оба loadPokemons и loadPokemonAdditionalInfo, как только ваш компонент монтируется.Вам нужно подождать, пока вы не получите имя покемонов, прежде чем вы получите их дополнительную информацию.

this.loadPokemonAdditionalInfo() должен быть вызван из обратного вызова setState, как

this.setState({
   isLoaded: true,
    names: json.results
}, this.loadPokemonAdditionalInfo)
0 голосов
/ 08 февраля 2019

Во-первых, когда вы попытаетесь загрузить дополнительные данные, имена не будут завершены.

Просто сделайте вашу 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));
0 голосов
/ 08 февраля 2019

Promise.all должен иметь массив или обещания, поэтому аргумент должен быть массивом выборок.

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]
    })
  })
...