0

I am working on a weather app, I fetch the data from an API in order to get the weather based on the latitude and longitude given from users' location. The website asks for the user's location on page load but I'm confused why I keep getting this error in the console:

enter image description here

I think the problem is because of the API fetch, but I am not sure and do not have a clear understanding of what is going on.

Here is the code:

import React, { useState, useEffect } from 'react';
import '../PageContent/PageContent.css';

const placeholderImg = 'https://i.pinimg.com/originals/e5/3c/fb/e53cfb282846313a69daf9755bfaf339.jpg';

const PageContent = () => {
  let api = '';

  const getLocation = () => {
    if (navigator.geolocation) navigator.geolocation.getCurrentPosition(showPosition);
    else document.body.innerHTML = 'Geolocation not supported.';
  };

  const showPosition = (position) => {
    api = `https://weather-proxy.freecodecamp.rocks/api/current?lat=${Math.round(
      position.coords.latitude,
    )}&lon=${Math.round(position.coords.longitude)}`;
  };

  getLocation();

  // Current date
  var curr = new Date();
  curr.setDate(curr.getDate());
  var date = curr.toISOString().substr(0, 10);

  // USE states

  const [celciusClick, setCelciusClick] = useState(false);
  const [farClick, setFarClick] = useState(true);

  const [weatherInfo, setWeatherInfo] = useState({
    location: '',
    weatherType: '',
    degrees: '',
    pressure: '',
    humidity: '',
    wind: '',
    icon: '',
    original: '',
  });

  useEffect(() => {
    fetch(api)
      .then((res) => res.json())
      .then((obj) => {
        console.log(obj);
        // variables to avoid verbose code
        var pressure = obj['main'].pressure;
        var weatherType = obj['weather'][0].description
          .toLowerCase()
          .split(' ')
          .map((s) => s.charAt(0).toUpperCase() + s.substring(1))
          .join(' ');
        var humidity = obj['main'].humidity + '%';
        var wind = Math.round(obj['wind'].speed) + ' mph';
        var degress = Math.round(obj['main'].temp);
        var icon = obj['weather'][0].icon;
        var original = Math.round(obj['main'].temp);
        var location = obj.name;

        // set info together
        setWeatherInfo({
          weatherType: weatherType,
          degrees: degress,
          pressure: pressure,
          humidity: humidity,
          wind: wind,
          icon: icon,
          original: original,
          location: location,
        });
      });
  }, []);

  const original = weatherInfo.original;
  // convert Far to Celcius .
  const HandleCelcius = () => {
    setFarClick(false);
    setCelciusClick(true);

    weatherInfo.degrees = (((weatherInfo.degrees - 32) * 5) / 9).toFixed(4);
  };
  // convert celcius .
  const HandleFar = () => {
    setCelciusClick(false);
    setFarClick(true);

    weatherInfo.degrees = original;
  };

  return (
    <div className="grid">
      <div className="weather-info">
        <h1>{weatherInfo.location}</h1>
        <h4>
          {weatherInfo.weatherType} <img src={weatherInfo.icon} height="35"></img>{' '}
        </h4>

        <input type="date" id="date" defaultValue={date} />
        <div>
          {weatherInfo.degrees}&#176;
          <button onClick={HandleFar} disabled={farClick}>
            F
          </button>
          <button onClick={HandleCelcius} disabled={celciusClick}>
            C
          </button>
        </div>
      </div>

      <div className="extra-info">
        <table>
          <tr>
            <td>Pressure: {weatherInfo.pressure}</td>
          </tr>
          <tr>
            <td>Humidity: {weatherInfo.humidity}</td>
          </tr>
          <tr>
            <td>Wind: {weatherInfo.wind}</td>
          </tr>
        </table>
        <div className="imgs">
          <div className="img">
            <figure>
              <img src={placeholderImg} width="100" />
              <figcaption>
                <h2>weather for this day</h2>
              </figcaption>
            </figure>
          </div>
        </div>
      </div>
    </div>
  );
};

export default PageContent;
Mario Petrovic
  • 7,500
  • 14
  • 42
  • 62
  • 2
    I haven't counted the lines to figure out what line 49 is, but it seems reasonably that this line: `.then((res) => res.json())` is causing the error. If you change that to `.then((res) => { console.log(res.text()); return res.json(); })` you'll still get the error, but the console will also show you what the server is returning to you. Is it *actually* returning JSON data or a HTML page? – rickdenhaan Feb 23 '21 at 00:04
  • @rickdenhaan It returns an HTML page. I am using the freecodecamp API (https://weather-proxy.freecodecamp.rocks/) – Jordan Moore Feb 23 '21 at 00:06
  • Alright, it shouldn't do that with the URL you're building. So the question is, does `api` contain the correct URL when you call `fetch(api)`? – rickdenhaan Feb 23 '21 at 00:12
  • @rickdenhaan Yes it returns **https://weather-proxy.freecodecamp.rocks/api/current?lat=42&lon=-88** which is correct based on my location – Jordan Moore Feb 23 '21 at 00:17
  • It seems like when I refresh the page, it functions correctly but when I save any edits in the live version in my code, then it throws the error at me – Jordan Moore Feb 23 '21 at 00:19
  • Since `getCurrentPosition` is async, and might return `undefined` if the user hasn't allowed the position permission for the website, which leaves the `api` as an empty string. – Emile Bergeron Feb 23 '21 at 00:23
  • 1
    I think @EmileBergeron is right and you have a bit of a race condition on your hands. Perhaps it would be better to have `api` be a state variable. `showPosition` can then update the state when the location is known, `useEffect` would need to have `api` as a dependency and check whether it's a proper URL before trying to `fetch` it. – rickdenhaan Feb 23 '21 at 00:56
  • I just implemented what you recommended and worked perfectly! Thanks a lot, @EmileBergeron and rickdenhaan. – Jordan Moore Feb 23 '21 at 02:31

0 Answers0