Routfin
Routfin

Reputation: 457

What would be the best solution to avoid this infinite loop (useEffect)

I developed an application where I get an api (pokeAPI) with pokemons, and basically I have a global array with "myPokemons", so I want to display all my pokemons except the ones in that array, so I created the function "filterMyPokemons" that I filter the pokemons that should be displayed, and then I call this function in useEffect so that it is updated along with the page, putting a dependency array from the API list. The problem is that I now have an infinite loop that hurts the performance of the application.

import * as C from './styles';

import logo from '../../assets/pokelogo.png';
import { useContext, useState } from 'react';
import { useApi } from '../../hooks/useApi';
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';


import Pokelist from '../../components/PokeList';

import CatchingPokemonIcon from '@mui/icons-material/CatchingPokemon';
import CatchContext from '../../context/Context';


const Homepage = () => {
    const api = useApi();
    const { showMyPokemons } = useContext(CatchContext);
    const navigate = useNavigate();

    const [pokemonList, setPokemonList] = useState([]);
    const [loading, setLoading] = useState(false);
    const [text, setText] = useState('');

    const [myPokemonsList, setMyPokemonsList] = useState([]);
    const [pokemonListFiltered, setPokemonListFiltered] = useState([]);

    useEffect (() => { 
        const getAllPokemons = async () => {
            const myPokemons = await showMyPokemons();
            const pokemon = await api.getAllPokemon();
            setLoading(true);
            setPokemonList(pokemon);
            setMyPokemonsList(myPokemons);
            setLoading(false); 
        }
        filterMyPokemons();
        getAllPokemons();    
    }, [myPokemonsList]); 
 
    const filterMyPokemons = async () => {
        const filteredList = await pokemonList.filter(pokemons => !myPokemonsList.includes(pokemons.name))
        return setPokemonListFiltered(filteredList);
    };  

    const lowerSearch = text.toLocaleLowerCase(); 
 
    const filteredPokemons = pokemonListFiltered.filter(pokemon => pokemon
        .name.toLowerCase().includes(lowerSearch)    
    );

    const handleHome = () => {
        navigate('/')
    }

    const handleMyPokemons = () => {
        navigate('/mypokemons')
    }


  return (
    <C.Container>
        <C.Logo>
            <img src={logo} alt="" />
        </C.Logo>
        <C.Navbar>
            <input 
                type="text" 
                placeholder='Busque um pokémon...'
                onChange={(e) => setText(e.target.value)}
                value={text}
            />
        </C.Navbar>
        <C.Pokedatabase onClick={handleMyPokemons}>
            <button>Meus pokémons <i><CatchingPokemonIcon /></i></button>
        </C.Pokedatabase>
        <C.Pokelist>
            {filteredPokemons.map(pokemon => { 
                return (
                    <Pokelist 
                        name={pokemon.name}
                    />
                )
            })}
        </C.Pokelist>
    </C.Container>
  )
}

export default Homepage;

If I leave useEffect's dependency array empty, the items are not displayed, but if I leave any dependencies it causes an infinite loop. How to solve this problem?

Upvotes: 0

Views: 37

Answers (1)

saguirrews
saguirrews

Reputation: 330

The problem comes with updating the myPokemonsList array within the useEffect hook that depends on that array.

useEffect (() => { 
        const getAllPokemons = async () => {
            const myPokemons = await showMyPokemons();
            const pokemon = await api.getAllPokemon();
            setLoading(true);
            setPokemonList(pokemon);
            setMyPokemonsList(myPokemons); // Here's the infinite loop
            setLoading(false); 
        }
        filterMyPokemons();
        getAllPokemons();    
    }, [myPokemonsList]); // Here's the infinite loop

You should have another use effect for updates on the myPokemonList in order to avoid updating and depending on the same list.

Upvotes: 1

Related Questions