简体   繁体   English

从 React 应用程序中的 api 获取数据之前的页面渲染导致错误

[英]Page rendering before the data fetch from api in React app is causing error

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.唯一的问题是页面在从 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?如何解决这个问题?

Simply don't try to access weather before you have it:只是不要在拥有天气之前尝试访问weather

{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.顺便说一句,这是一种更惯用的代码编写方式,嵌套函数更少, async / await更多以减少嵌套。

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;

variable weather has no value before API call response so add this condition变量weather在 API 调用响应之前没有值所以添加这个条件

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM