1

I'm using the following component for the Nav. And on this navabar I want to display the weather of user's current location. The only problem is that the page is rendering before fetching the data from the openWeather api.

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

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


const Nav = () => {

  useEffect(() => {

    const successfulLookup = position => {
      const { latitude, longitude } = position.coords;
      fetch(`https://api.opencagedata.com/geocode/v1/json?q=${latitude}+${longitude}&key=mykey`)
        .then(response => response.json())
        .then(result => {
          const query = result.results[0].components.city;
          weatherOnLoad(query);
        })
    };

    const weatherOnLoad = query => {
      fetch(`${api.base}weather?q=${query}&units=metric&APPID=${api.key}`)
        .then(res => res.json())
        .then(result => {
          setWeather(result);
          console.log(result);
        });
    };

    // successfulLookup();

    if (window.navigator.geolocation) {
      window.navigator.geolocation
       .getCurrentPosition(successfulLookup, console.log);
    }
  }, []);


  const [weather, setWeather] = useState({});

  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 `${month} ${date}, ${year} | ${day}`
  }


  return (
    <nav className="navbar navbar-expand-lg navbar-light bg-light">
      <a className="navbar-brand" href="/#">Get-Set-Note</a>
      <div className="date">{dateBuilder(new Date())}</div>
      <div className="temp">
        {Math.round(weather.main.temp)}°c
      </div>
    </nav>
  );
};

export default Nav;

Because of this I'm getting this error:

TypeError: Cannot read property 'temp' of undefined

How to resolve this problem?

1

2 Answers 2

2

Simply don't try to access weather before you have it:

{weather && weather.main ? <div className="temp">{Math.round(weather.main.temp)}°c</div> : null}

As an aside, here's a more idiomatic way to write your code, with less nested functions and more async/await to reduce nesting.

import React, { useState, useEffect } from "react";

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

const months = [
  "January",
  "February",
  "March",
  "April",
  "May",
  "June",
  "July",
  "August",
  "September",
  "October",
  "November",
  "December",
];
const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];

function formatDate(d) {
  const day = days[d.getDay()];
  const date = d.getDate();
  const month = months[d.getMonth()];
  const year = d.getFullYear();
  return `${month} ${date}, ${year} | ${day}`;
}

async function getWeatherForCoordinates(latitude, longitude) {
  const cityResp = await fetch(`https://api.opencagedata.com/geocode/v1/json?q=${latitude}+${longitude}&key=mykey`);
  const result = await cityResp.json();
  const query = result.results[0].components.city;
  const weatherResp = await fetch(`${api.base}weather?q=${query}&units=metric&APPID=${api.key}`);
  const weather = await weatherResp.json();
  return weather;
}

// Promisified `geolocation.getCurrentPosition`
async function getCurrentPositionP() {
  return new Promise((resolve, reject) => {
    if (!window.navigator.geolocation) {
      return reject("No geolocation");
    }
    window.navigator.geolocation.getCurrentPosition(resolve, reject);
  });
}

async function getLocalWeather() {
  const position = await getCurrentPositionP();
  const { latitude, longitude } = position.coords;
  const weather = await getWeatherForCoordinates(latitude, longitude);
  return weather;
}

const Nav = () => {
  const [weather, setWeather] = useState(null);
  useEffect(() => {
    getLocalWeather().then(setWeather, console.error);
  }, []);

  return (
    <nav className="navbar navbar-expand-lg navbar-light bg-light">
      <a className="navbar-brand" href="/#">
        Get-Set-Note
      </a>
      <div className="date">{formatDate(new Date())}</div>
      {weather ? <div className="temp">{Math.round(weather.main.temp)}°c</div> : null}
    </nav>
  );
};

export default Nav;
Sign up to request clarification or add additional context in comments.

Comments

2

variable weather has no value before API call response so add this condition

{weather.main ? Math.round(weather.main.temp) : ''}°c

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.