1

i am using fetch API to fetch from an API.
After fetching the result i want to setState to the reult which is not working
this is the function that fetches the results

export const random = (min, max) => Math.floor(Math.random() * (max - min)) + min;


export const getPokemons = async function () {
  const pokemon = [];
  for (let i = 0; i < 5; i++) {
    pokemon.push(fetch(`https://pokeapi.co/api/v2/pokemon/${random(1, 800)}`));
  }
  return Promise.all(pokemon)
    .then((data) => {
      const parsedData = [];
      data.forEach(async (d) => {
        const resJson = await d.json()
        parsedData.push(resJson);
      });
       return parsedData
    })
    .catch((err) => {
      console.log(err);
    });
};

the code where it is imported

  const [stats,setStats] = useState([])
  useEffect(()=>{
      generateTrio()  
        },[])
        
    async function generateTrio() {
        const gTrio = await getPokemons();
        setStats(gTrio)
        console.log(stats,gTrio)
        }

stats here is an empty array , while gTrio is required results i want to be in setStats

Hussam Khatib
  • 600
  • 6
  • 17
  • Don't log `stats` after calling `setStats()`, just use `stats` to render your elements and it will work like you expect. – Patrick Roberts Nov 28 '20 at 05:57
  • @PatrickRoberts i'm sure that it's an emty array even after the `setState` is called. [link to codesanbbox](https://codesandbox.io/s/sharp-roentgen-chre5?file=/src/App.js) – Hussam Khatib Nov 28 '20 at 06:09

2 Answers2

1

The problem is twofold:

Your getPokemons() was returning an empty array from your asynchronous function, and then asynchronously populating it after it's used to render your Main component.

Even if you were logging stats in the correct closure, Chrome's developer console output would be confusing since it would show you that the array was populated even though it was empty at the time it was logged. See Is Chrome's JavaScript console lazy about evaluating arrays? for more information about this developer console behavior.

One correct way to write getPokemons() would be:

export const getPokemons = () => (
  Promise.all(
    Array.from({ length: 5 }, async () => {
      const response = await fetch(`https://pokeapi.co/api/v2/pokemon/${random(1, 800)}`);
      return response.json();
    })
  )
);

And a correct way to write your Main component would be:

const Wrapper = styled.div``;

const Main = () => {
  const [stats, setStats] = useState([]);

  useEffect(() => {
    const setPokemons = async () => {
      setStats(await getPokemons());
    };

    setPokemons();  
  }, []);

  // console.log(stats);

  const names = stats.map(item => ( 
    <p key={item.id}>{item.name}</p> 
  ));

  return (
    <Wrapper>
      {names}
    </Wrapper>
  );
}

export default Main;
Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153
0

Set function of usestate does not set state immediately and synchronous. I think it like async method. Bu it is not only real reason. You can check this message at similar topic. https://stackoverflow.com/a/58877875/12239744

Emin Deniz
  • 44
  • 1
  • 2