skip to Main Content

Im learning react and this is some demo code I have written. It does an initial request even though it’s inside of an useEffect with dependency. Why does it do that and how can i fix it?

import { useEffect, useState } from "react";
import BasicInfo from "./BasicInfo";

export default function MainInfo(){
    const [searchByName, setSearchByName] = useState('');
    const [pokemonInfo, setPokemonInfo] = useState({});
    const [hasInfo, setHasInfo] = useState(false);
    const [hasPressed, setHasPressed] = useState(false);

    const handleSubmit = (e) =>{
        e.preventDefault();
        setHasPressed(true);
        console.log(searchByName);
    };
    const changeHandler = (e) =>{
        setSearchByName(e.target.value);
        setHasPressed(false);
    };
    const buttonHandler = (e) =>{
        setHasPressed(oldState => !oldState);
    }

    useEffect(() => {
        fetch(`https://pokeapi.co/api/v2/pokemon/${searchByName}`)
            .then(response => response.json())
            .then(data => {
                console.log(data)
                setPokemonInfo(data)
                setHasInfo(true)

            })
            .catch(error => console.error('Error fetching data', error))
    },[hasPressed])
    
    return(
        <div>
            <form onSubmit={handleSubmit}>
                <input type="text" name="input" value={searchByName} onChange={changeHandler}></input>
                <button onClick={buttonHandler}></button>
            </form>
            {hasInfo && pokemonInfo.abilities && (
                <div>
                    <BasicInfo
                        name={pokemonInfo.name}
                        abilities={pokemonInfo.abilities}
                    />
                </div>
            )}
        </div>
    );
}

What I have tried:

I tried adding state which would change whenever the button is pressed and it’s not used for anything else so it doesn’t matter if it’s true or false. It didn’t fix the problem

2

Answers


  1. useEffect triggers on the dependency changes, but the initial run is treated as a change as well. If you don’t want to to the fetch until hasPressed, wrap the fetch in an if

        useEffect(() => {
          if(hasPressed){
            fetch(`https://pokeapi.co/api/v2/pokemon/${searchByName}`)
                .then(response => response.json())
                .then(data => {
                    console.log(data)
                    setPokemonInfo(data)
                    setHasInfo(true)
    
                })
                .catch(error => console.error('Error fetching data', error))
          }
        },[hasPressed])
    
    Login or Signup to reply.
  2. remove the useEffect, you don’t need it

    just trigger the function onSubmit

    and get rid of onClick, and add a type="submit" to your button.

    you do not need hasPressed state anymore.

        import { useState } from "react";
        import BasicInfo from "./BasicInfo";
    
        export default function MainInfo() {
        const [searchByName, setSearchByName] = useState("");
        const [pokemonInfo, setPokemonInfo] = useState({});
        const [hasInfo, setHasInfo] = useState(false);
    
        const handleSubmit = (e) => {
            e.preventDefault();
    
            console.log(searchByName);
            fetch(`https://pokeapi.co/api/v2/pokemon/${searchByName}`)
            .then((response) => response.json())
            .then((data) => {
                console.log(data);
                setPokemonInfo(data);
                setHasInfo(true);
            })
            .catch((error) => console.error("Error fetching data", error));
        };
        const changeHandler = (e) => {
            setSearchByName(e.target.value);
        };
    
        return (
            <div>
            <form onSubmit={handleSubmit}>
                <input
                type="text"
                name="input"
                value={searchByName}
                onChange={changeHandler}
                ></input>
                <button type="submit"></button>
            </form>
            {hasInfo && pokemonInfo.abilities && (
                <div>
                <BasicInfo
                    name={pokemonInfo.name}
                    abilities={pokemonInfo.abilities}
                />
                </div>
            )}
            </div>
        );
        }
    

    Also you don’t need hasInfo state, you can replace "hasInfo && pokemonInfo.abilities" by "pokemonInfo && pokemonInfo.abilities"

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search