1

I'm trying to display an array with 151 pokemons sorted by their pokedex positions (ex: 1 - bulbasaur, 2- ivysaur...), but every time I reload the page it brings me a different array, with the positions shuffled.

App.js:

import './App.css';
import { useEffect, useState } from 'react';
import Pokemon from './components/Pokemon';

const App = () => {
  const [pokemonData, setPokemonData] = useState([]);

  const fetchPokemons = () => {
    for (let index = 1; index < 152; index += 1) {
      new Array(151).fill(
        fetch(`https://pokeapi.co/api/v2/pokemon/${index}`)
          .then((data) => data.json())
          .then((result) =>
            setPokemonData((prevState) => [...prevState, result])
          )
      );
    }
  };

  useEffect(() => {
    fetchPokemons();
  }, []);

  return (
    <>
      {pokemonData && <Pokemon data={pokemonData} />}
    </>
  );
};

export default App;

Pokemon.js:

const Pokemon = ({ data }) => {
  return (
    <section>
      {data.map((pokemon) => (
        <div key={pokemon.name}>
          <img src={pokemon.sprites.front_default} alt={pokemon.name} />
          <span>{pokemon.name}</span>
          <span>
            {pokemon.types.length >= 2
              ? `${pokemon.types[0].type.name}  ${pokemon.types[1].type.name}`
              : pokemon.types[0].type.name}
          </span>
        </div>
      ))}
    </section>
  );
};

export default Pokemon;

1
  • 1
    Your current code is building a new array for each pokémon, and filling it with... well, undefined, eventually. The shuffling is due to the promises (of which you are currently making 151 of in parallel) resolving in an arbitrary order. Commented Mar 27, 2022 at 20:17

2 Answers 2

2

If you want to guarantee the order, you'll need something like

  const fetchPokemons = async () => {
    const promises = [];
    for (let index = 1; index < 152; index += 1) {
      promises.push(fetch(`https://pokeapi.co/api/v2/pokemon/${index}`).then((data) => data.json()));
    }
    const results = await Promise.all(promises);
    setPokemonData(results);
  };

This will take a while as it loads all of the pokémon before showing any of them - if you don't want that, then there really are two options: rework things to do each request sequentially, or alternately switch to an array where some of the slots may be null while things are still being loaded (which will require changing your rendering code some too).

Sign up to request clarification or add additional context in comments.

2 Comments

It is still possible to have race condition while awaiting all promises here await Promise.all(promises), it is not 100% that request that is fire first will finish first. To ensure that pokemons are sorted, it must eather wait for every call (which is slow), sort them after await Promise.all(promises); line, or get all pokemons at once from a single API call if there is backend api support for that. Please correct me if I'm wrong..
@Wings Promise.all() only resolves once all of the promises in the array resolve, or when any of them rejects. There is no race condition here, only slowness.
1

You are making 153 calls to api, which is not great I would highly recommend that you change into single api call to get all pokemons, to achieve this you can do it like this:

const [pokemonData, setPokemonData] = useState<any>([]);

  const fetchPokemons = async () => {
      const data = await fetch(`https://pokeapi.co/api/v2/pokemon?offset=0&limit=153"`);
      const pokemons = await data.json();
      setPokemonData(pokemons.results);
  };

  useEffect(() => {
    (async () => {
      await fetchPokemons();
    })();
  }, []);

Also this will guarantee that you get data always in the same way. You will not face any race conditions and you won't any unnecessary api calls.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.