1

I'm still beginner to ReactJS and I'm having trouble rendering a list.

I don't know why, all the time calls are being made to my API. Since I don't put any dependency on useEffect, that is, I should only render my function once.

I don't understand why this is happening. Can you tell me what I'm doing wrong?

Here's my code I put into codesandbox.io

import React from "react";
import axios from "axios";
import "./styles.css";

const App = () => {
  const BASE_URL = "https://pokeapi.co/api/v2";

  const [pokemons, setPokemons] = React.useState([]);

  const getAllPokemons = async () => {
    const { data } = await axios.get(`${BASE_URL}/pokemon`);

    data.results.map((pokemon) => getPokeType(pokemon));
  };

  const getPokeType = async (pokemon) => {
    const { data } = await axios.get(pokemon.url);

    setPokemons((prev) => [...prev, data]);
  };

  React.useEffect(() => {
    getAllPokemons();
  }, []);

  console.log(pokemons);

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      {pokemons.map((pokemon) => (
        <p key={pokemon.id} style={{ color: "blue" }}>
          {pokemon.name}
        </p>
      ))}
    </div>
  );
};

export default App;

enter image description here

Thank you very much in advance.

2
  • 2
    It might come from the fact that your getPokeType method is async and this is causing the react lifecycle to act out. Try this const datas = await Promise.all( data.results.map((pokemon) => axios.get(pokemon.url)) ); setPokemons(datas); instead of data.results.map((pokemon) => getPokeType(pokemon));
    – Marko Taht
    Commented Jun 25, 2022 at 21:10
  • 2
    Here is a small refactor that gives the effect you want, as Marko mentioned. Then, you can set the state only once at the end, which is cleaner anyways. codesandbox.io/s/stoic-leavitt-ngokv9 Commented Jun 25, 2022 at 21:18

2 Answers 2

1

Your issue is that you are calling setPokemons inside getPokeType (which is called for each data in part). Your useEffect is called just once (as expected) and the ${BASE_URL}/pokemon call is executed just once too. But getPokeType is called 20 times and the pokemons state is changed 20 times as well (once for each instance from data.results).

What I would recommend in your case (instead of what you have now) is:

  1. Create a list of all the pokemons and
  2. Set the state just once at the end.

So something like:

  ...

  const getPokeType = async (pokemon) => {
    const { data } = await axios.get(pokemon.url);
    return data;
  };
  const getAllPokemons = async () => {
    const { data } = await axios.get(`${BASE_URL}/pokemon`);
    const pokemons = await Promise.all(
      data.results.map((pokemon) => getPokeType(pokemon))
    );
    setPokemons(pokemons);
  };

  React.useEffect(() => {
    getAllPokemons();
  }, []);
  ...
1
  • 1
    Just an additional note, because the Codesandbox react is running in strict mode, the component is actually rendering at least twice - because he is concatenating the previous state with the new state as well, it's causing more than 20 items to build up. Also because of the conflicting keys I believe it was triggering even more re-renders, at one point I saw up to 75 items in the current state. Commented Jun 25, 2022 at 21:57
0

I was just having the same issue in my project the way I solved is by moving the function definition inside the useEffect

     React.useEffect(() => {
             const getAllPokemons = async () => {
             const { data } = await axios.get(`${BASE_URL}/pokemon`);

             data.results.map((pokemon) => getPokeType(pokemon));
         };
      getAllPokemons();
     }, []); 

If this solves your problem please accept the answer.

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.