Home > Blockchain >  Trying to refresh Open Weather Api every 3 or 30 seconds
Trying to refresh Open Weather Api every 3 or 30 seconds

Time:08-28

I created a simple weather web app from a youtube video and I wanted it to refresh every 3 or 30 seconds automatically but I'm getting an unidentified error when I try to use setInterval:

App.js:15 Uncaught TypeError: Cannot read properties of undefined (reading 'key') at search (App.js:15:1)

I just started react-js, here's my code:

import './App.css';

import React,{ useState } from 'react';

const api = {
  key: "5f285d33be01b937453b7e1688fc75ee",
  base:"https://api.openweathermap.org/data/2.5/"
}

function App() {
  const [query, setQuery] = useState('');
  const [weather, setWeather] = useState({});

  const search = evt => {
    if (evt.key === "Enter") {
      fetch(`${api.base}weather?q=${query}&units=metric&APPID=${api.key}`)
      .then(res => res.json())
      .then(result => {
        setWeather(result);
        setQuery('');
        console.log(result);
      });
    }
  }
//

  const dateBuilder = (d) =>{
    let months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
    let days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];

    let day = days[d.getDay()];
    let date = d.getDate();
    let month = months[d.getMonth()];
    let year = d.getFullYear();
    
    return `${day} ${date} ${month} ${year}`
  }

  function round(value, precision) {
    var multiplier = Math.pow(10, precision || 0);
    return Math.round(value * multiplier) / multiplier;
}

  return (
    <div className={(typeof weather.main != "undefined")? ((weather.main.temp > 9) ? ((weather.weather[0].main == 'Rain')? 'app rain': ((weather.weather[0].main == 'Clouds')? 'app clouds': 'app warm')) : 'app'): 'app'}>
      <main>
        <div className='search-box'>
          <input type="text" className='search-bar' placeholder='Search...' onChange={e => setQuery(e.target.value)} value={query} onKeyPress={search}/>
        </div>
        {(typeof weather.main != "undefined") ? (
        <div><div className='loaction-box'>
          <div className='location'>
            {weather.name}, {weather.sys.country}
            </div>
          <div className='date'>{dateBuilder(new Date())}</div>
          
          <div className='weather-box'>
            <div className='temp'>{Math.round(weather.main.temp)}°c
            <div className='weather-small'>Humidity: {weather.main.humidity}% <br/> Wind: {round(weather.wind.speed,1)}km/h</div>
            <div className='weather-small'></div>

            </div>
            

            <div className='weather'>{weather.weather[0].description}</div>
          </div>
        </div> </div>): ('')}

      </main>
    </div>
  );
}

export default App;

CodePudding user response:

change onKeyPress with onKeyDown and it's event has key property

CodePudding user response:

There is no setInterval in the shared code snippet but based on the code and the included error message I am assuming you tried passing search as the interval callback.

setInterval(search, 3000);

The issue here is that search expects to be passed an onKeyPress event object.

const search = evt => {
  if (evt.key === "Enter") { // <-- evt undefined
    fetch(`${api.base}weather?q=${query}&units=metric&APPID=${api.key}`)
      .then(res => res.json())
      .then(result => {
        setWeather(result);
        setQuery('');
        console.log(result);
      });
  }
}

I suggest refactoring the code a bit. Factor out the fetching logic from the keypressing logic. Create a onKeyPress handler that invokes the search callback and passes the query state, and use a useEffect hook with a dependency on the query state to instantiate an interval timer.

Example:

const search = async (query) => {
  try {
    const res = await fetch(`${api.base}weather?q=${query}&units=metric&APPID=${api.key}`);
    const result = await res.json();
    setWeather(result);
    console.log(result);
  } catch (error) {
    // catch & handle any Promise rejections and thrown errors
  }
}

const keyPressHandler = async (evt) => {
  if (evt.key === "Enter") {
    await search(query);
    setQuery('');
  }
}

useEffect(() => {
  let timer = null;
  if (query) {
    timer = setInterval(search, 3000, query);
  }
  return () => clearInterval(timer);
}, [query]);
  • Related