skip to Main Content

I am trying to display data fetched from API with React.

I am fetching the data from https://pokeapi.co/docs/v2, and I intend to display the names and urls retuned and also manipulate them to practice conditional rendering, etc

But it seems that I have run into an infinite loop.

I have googled and it suggests me to use React.useEffect() But even if I did this, I still get the errors:

Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.

My code are as below:

App.js

import React from 'react'
import PokemonList from "./PokemonList";

function App() {

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

  React.useEffect(() => {
    console.log('fetch ran')
    fetch('https://pokeapi.co/api/v2/pokemon').then(res => res.json())
      .then(data => {
        setPokemons(() => data);
      })
  }, [])

  return (
    <div>
      <PokemonList pokemons={pokemons} />
    </div>
  )
}

export default App;

PokemonList.js:

import React from 'react'

export default function PokemonList({ pokemons }) {

    const [pokemonsArray, setPokemonsArray] = React.useState([]);

    setPokemonsArray(()=>pokemons.results)

    const pokemonsElements = pokemonsArray.map((pokemon) => {
        return (
            <div key={pokemon.name}>
                <h3>{pokemon.name}</h3>
                <p>{pokemon.url}</p>
                <hr />
            </div>
        )
    })
    return (
        <div>
            {pokemonsElements}
        </div>
    )
}

Sometimes I would also get the error:

Consider adding an error boundary to your tree to customize error handling behavior.
react-refresh-runtime.development.js:315 Uncaught TypeError: Cannot read properties of undefined (reading 'map')

I assume this is bc I try to run .map() when the data has not been returned yet….

Can anyone help me? Sorry if it is a stupid question but I have been stuck for so long and could not find answers. What is the correct way to do this?

2

Answers


  1. You’re trying to set the state directly inside the component which means that every time the component renders, and its state is updated which causes a re-render and then you set the state again, causing another re-render.

    It is exactly as you stated. The reason map in pokemonsArray.map is being undefined is because it is immediately being accessed before the component is mounted and is ready.

    Here is how you would do it by fixing in App and PokemonList

    In App, you do not need to make a callback on setPokemons as you can directly pass the value.

    setPokemons(data || [])
    

    App:

    const [pokemons, setPokemons] = React.useState([]);
    
    React.useEffect(() => {
      console.log('fetch ran')
      fetch('https://pokeapi.co/api/v2/pokemon')
        .then(res => res.json())
        .then(data => {
          setPokemons(data.results || []);
        })
    }, [])
    

    Check if pokemons is unavailable in which case return null or call a spinner component or similar which shows that the list is empty or being loaded.

    PokemonList

    export default function PokemonList({ pokemons }) {
      if (!pokemons) return null;
    
      return (<div> {
        pokemons.map((pokemon) => (
          <div key={pokemon.name}>
            <h3>{pokemon.name}</h3>
            <p>{pokemon.url}</p>
            <hr />
          </div>
        ))}
      </div>)
    }
    
    Login or Signup to reply.
  2. The error is in this line:

    setPokemonsArray(()=>pokemons.results)

    Btw, I recommend the use of react-query.

    With RQ:

    import React from 'react'
    import PokemonList from "./PokemonList";
    
    function App() {
      const {data: pokemons} = useQuery(
        queryKey: ['pokemons'],
        queryFn: () =>
          fetch('https://pokeapi.co/api/v2/pokemon').then(
            (res) => res.json(),
          ))
    
      return (
        <div>
          <PokemonList pokemons={pokemons} />
        </div>
      )
    }
    
    export default App;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search