Search code examples
reactjsreact-hooksweather-api

UseState is not updating inside useEffect


I am reaching out to you for help with an issue in my code. I have done a lot of research and tried different approaches, but I still can't solve this problem.

I need help with React code. Specifically, I want to achieve that when the page is loaded or refreshed, if the state is empty, it should automatically get the value of the city name (for example, London) and make a request to the API.

I used useEffect for this purpose, but I couldn't achieve the desired result using useState. Since useState remains empty during the execution of the request. I also tried adding setTimeout, but it didn't help either. Therefore, I am forced to ask for help because, regardless of anything, I want to understand what the problem is and move on.

If you have any ideas or suggestions, I would be infinitely grateful. I really appreciate any help you can give me.

Here's the code:

const [location, setLocation] = useState('');
const [apiData, setApiData] = useState(null);
const api_key = "1746befa30558443451784583d966d81";

const gettingWeather = async () => {
const url = `https://api.openweathermap.org/data/2.5/forecast/?q=${location}&cnt=60&units=metric&appid=${api_key}`; 

try {
  const response = await axios.get(url);
  setApiData(response.data);
  console.log(response.data);
} catch (err) {
  console.log(err);
}
}


/*------------------------------------------------------------------*/

useEffect(() => {
   const storedLocation = localStorage.getItem('location');
   if (storedLocation) {
     setLocation(storedLocation);
     console.log(storedLocation);
     gettingWeather();
   } else {
   
     localStorage.setItem('location', 'London');
     gettingWeather();
   }
  setLocation('London');
  console.log('hello');
  
}, [])


useEffect(() => {
  const timer = setTimeout(() => {
    
    gettingWeather();
    console.log(location);
  }, 1000);
  return () => clearTimeout(timer); // Clear the timer on unmount
}, []);

/*------------------------------------------------------------------*/




/*JSX*/    
<input 
  type = "text"
  onChange = {event => setLocation(event.target.value)}
  placeholder = "Your location"
  className ='input-loc'
  />
  <button onClick={ gettingWeather} className='search-button' >
  <img src={require("./img/search.png")} alt="" className="panel-image"/>
  </button>

Solution

  • You need to make the gettingWeather() change when location changes, so add dependency and useCallback.

    const gettingWeather = React.useCallback( async () => {
        // Same As Before
    },[location])
    

    And then make the use effect dependent on changes to the gettingWeather function.

    useEffect(() => {
      const timer = setTimeout(() => {
        
        gettingWeather();
        console.log(location);
      }, 1000);
      return () => clearTimeout(timer); // Clear the timer on unmount
    }, [gettingWeather]);