skip to Main Content

I am a beginner in react and trying a basic example where I am fetching data based on what I am passing in input field , the value in input field goes as id to the API URL , Everything is working fine but
this fails for a particular case . Suppose I entered 3 in input field and then click the button , First time the data shows as expected , but if I again press the get data button the UI just stuck showing Loading…
I think it is related to dependency array in useEffect.

import React,{useState,useEffect} from 'react'

const FetchData = () => {
  const [data,setData]=useState({})
  const [value,setValue]=useState(1)
  const [id,setId]=useState(1)
  const [loading,setLoading]=useState(true)

  const idUpdater=()=>{
    setLoading(true)
    setId(value)
  }
  
  useEffect(()=>{
    const fetchData= async()=>{
       const data=await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`)
       const response=await data.json()
       setData(response)
       setLoading(false)
    }
    setTimeout(fetchData,2000)  
  },[id])

  
  
  return (

    <div>
    <input type="text" value={value} onChange={(e)=>setValue(e.target.value)} />
    <button onClick={idUpdater}>Get Data</button>
    {loading?<h1>Loading...</h1>:<h1>{data.title}</h1>}
    </div>
  )
}

export default FetchData

I tried removing the dependency array , but it didn’t work

2

Answers


  1. Based on the condition you have given the code in useEffect gets only rendered when the id is different. When you press the button again the id remains same thus the code inside useEffect won’t run and the loading state set in idUpdater will remain true.

    A better approach to this would be calling fetch on initial mount and reusing that function on button press, as:

    import React, { useState, useEffect } from "react";
    
    const FetchData = () => {
      const [data, setData] = useState({});
      const [value, setValue] = useState(1);
      const [loading, setLoading] = useState(true);
    
      const idUpdater = () => {
        setLoading(true);
        fetchData(value);
      };
    
      const fetchData = async (pageNo) => {
        const data = await fetch(
          `https://jsonplaceholder.typicode.com/posts/${pageNo}`
        );
        const response = await data.json();
        setData(response);
        setLoading(false);
      };
    
      useEffect(() => {
        fetchData(1);
      }, []);
    
      return (
        <div>
          <input
            type="text"
            value={value}
            onChange={(e) => setValue(e.target.value)}
          />
          <button onClick={idUpdater}>Get Data</button>
          {loading ? <h1>Loading...</h1> : <h1>{data.title}</h1>}
        </div>
      );
    };
    
    export default FetchData;
    

    Check demo

    Login or Signup to reply.
  2.   useEffect(()=>{
        const fetchData= async()=>{
           const data=await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`)
           const response=await data.json()
           setData(response)
           setLoading(false)
        }
        setTimeout(fetchData,2000)  
      },[id])
    

    The dependencies inside the square brackets means, this useEffect will be triggered everytime the id changes.

    In your case, when re-clicking the Get data button, setLoading(true) runs make your ui runs into Loading… state, the setId(value) also runs but the value does not change (still 3) therefore the useEffect is not triggered

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