1

我正在使用 Geolocation 制作一个初学者 React 天气应用程序。这是代码。主要代码在App.js中。DailyHourly仅用于显示。

应用程序.js

import React, { useState, useEffect } from "react";
import Hourly from "./Components/Hourly";
import Daily from "./Components/Daily";

const App = () => {
    const [currentWeatherOne, setCurrentWeatherOne] = useState({});
    const [currentWeatherTwo, setCurrentWeatherTwo] = useState({});
    const [currentWeatherThree, setCurrentWeatherThree] = useState({});
    const [currentWeatherFour, setCurrentWeatherFour] = useState({});
    const [currentWeatherFive, setCurrentWeatherFive] = useState({});
    const [lat, setLat] = useState();
    const [long, setLong] = useState();
    const [today, setToday] = useState();
    const [tomorrow1, setTomorrow1] = useState({});
    const [tomorrow2, setTomorrow2] = useState({});
    const [refreshText, setRefreshText] = useState();

    const getPosition = () => {
        return new Promise((resolve, reject) => {
            navigator.geolocation.getCurrentPosition(resolve);
        });
    };

    const getWeather = async (lat, long) => {
        let a = await fetch(
            `https://api.openweathermap.org/data/2.5/forecast?lat=${lat}&lon=${long}&appid=dcadf332823cddfb979926a1414274e8&units=metric`
        );
        let b = await a.json();
        console.log(b);
        setCurrentWeatherOne(b.list[1]);
        setCurrentWeatherTwo(b.list[2]);
        setCurrentWeatherThree(b.list[3]);
        setCurrentWeatherFour(b.list[4]);
        setCurrentWeatherFive(b.list[5]);
        setToday(b.list[0]);
        setTomorrow1(b.list[11]);
        setTomorrow2(b.list[19]);
    };

    useEffect(() => {
        getPosition().then(data => {
            setLat(data.coords.latitude);
            setLong(data.coords.longitude);
            getWeather(data.coords.latitude, data.coords.longitude);
        });
    }, []);

    // console.log(currentWeatherOne, currentWeatherThree, currentWeatherFive);

    const refresh = () => {
        getWeather(lat, long);
        let hours = String(new Date().getHours());
        let minutes = String(new Date().getMinutes());
        let seconds = String(new Date().getSeconds());
        setRefreshText(
            `Updated as of: ${hours}:${minutes.length < 2 ? "0" : ""}${minutes}:${
            seconds.length < 2 ? "0" : ""
            }${seconds}`
        );
    };

    return (
        <div className="App">
            <header>Geolocation weather</header>
            <button onClick={refresh}>Refresh</button>
            <br />
            {refreshText}
            <hr />
            <h3>Hourly</h3>
            <div className="container-2">
                <Hourly
                    icon={currentWeatherOne.weather[0].icon}
                    time={currentWeatherOne.dt_txt}
                    minTemp={currentWeatherOne.main.temp_min}
                    maxTemp={currentWeatherOne.main.temp_max}
                    description={currentWeatherOne.weather[0].description}
                    humidity={currentWeatherOne.main.humidity}
                />
                <Hourly
                    icon={currentWeatherTwo.weather[0].icon}
                    time={currentWeatherTwo.dt_txt}
                    minTemp={currentWeatherTwo.main.temp_min}
                    maxTemp={currentWeatherTwo.main.temp_max}
                    description={currentWeatherTwo.weather[0].description}
                    humidity={currentWeatherTwo.main.humidity}
                />
                <Hourly
                    icon={currentWeatherThree.weather[0].icon}
                    time={currentWeatherThree.dt_txt}
                    minTemp={currentWeatherThree.main.temp_min}
                    maxTemp={currentWeatherThree.main.temp_max}
                    description={currentWeatherThree.weather[0].description}
                    humidity={currentWeatherThree.main.humidity}
                />
                <Hourly
                    icon={currentWeatherFour.weather[0].icon}
                    time={currentWeatherFour.dt_txt}
                    minTemp={currentWeatherFour.main.temp_min}
                    maxTemp={currentWeatherFour.main.temp_max}
                    description={currentWeatherFour.weather[0].description}
                    humidity={currentWeatherFour.main.humidity}
                />
                <Hourly
                    icon={currentWeatherFive.weather[0].icon}
                    time={currentWeatherFive.dt_txt}
                    minTemp={currentWeatherFive.main.temp_min}
                    maxTemp={currentWeatherFive.main.temp_max}
                    description={currentWeatherFive.weather[0].description}
                    humidity={currentWeatherFive.main.humidity}
                />
            </div>
            <h3>Daily</h3>
            <div className="container-1">
                <Daily
                    icon={today.weather[0].icon}
                    time={today.dt_txt}
                    minTemp={today.main.temp_min}
                    maxTemp={today.main.temp_max}
                    description={today.weather[0].description}
                    humidity={today.main.humidity}
                />
                <Daily
                    icon={tomorrow1.weather[0].icon}
                    time={tomorrow1.dt_txt}
                    minTemp={tomorrow1.main.temp_min}
                    maxTemp={tomorrow1.main.temp_max}
                    description={tomorrow1.weather[0].description}
                    humidity={tomorrow1.main.humidity}
                />
                <Daily
                    icon={tomorrow2.weather[0].icon}
                    time={tomorrow2.dt_txt}
                    minTemp={tomorrow2.main.temp_min}
                    maxTemp={tomorrow2.main.temp_max}
                    description={tomorrow2.weather[0].description}
                    humidity={tomorrow2.main.humidity}
                />
            </div>
        </div>
    );
};

export default App;

日常的

import React from "react";

const Daily = ({ icon, time, minTemp, maxTemp, description, humidity }) => {
  let timeToShow = time.split(" ")[0];
  let one = timeToShow.split("-")[0];
  let two = timeToShow.split("-")[1];
  let three = timeToShow.split("-")[2];

  maxTemp = Math.floor(maxTemp);
  minTemp = Math.floor(minTemp);
  description = description
    .split(" ")
    .map(word => {
      return word[0].toUpperCase() + word.substring(1);
    })
    .join(" ");

  return (
    <div className="weather">
      <div>
        {three}-{two}-{one}
      </div>
      <img
        src={`https://openweathermap.org/img/w/${icon}.png`}
        alt="weather icon"
      />
      <div>
        <div>
          <span className="temp">{maxTemp}</span>
          <span>{minTemp}</span>
        </div>
        <br />
        <div>{description}</div>
        <br />
        {humidity}% humidity
      </div>
    </div>
  );
};

export default Daily;

每小时

import React from "react";

const Hourly = ({ description, humidity, time, icon, minTemp, maxTemp }) => {
  let timeToShow = time.split(" ")[1];
  let first = timeToShow.split(":")[0];
  let second = timeToShow.split(":")[1];
  maxTemp = Math.floor(maxTemp);
  minTemp = Math.floor(minTemp);
  description = description
    .split(" ")
    .map(word => {
      return word[0].toUpperCase() + word.substring(1);
    })
    .join(" ");

  return (
    <div className="weather">
      <div>
        {first}:{second}
      </div>
      <img
        src={`https://openweathermap.org/img/w/${icon}.png`}
        alt="weather icon"
      />
      <div>
        <div>
          <span className="temp">{maxTemp}</span>
          <span>{minTemp}</span>
        </div>
        <br />
        <div>{description}</div>
        <br />
        {humidity}% humidity
      </div>
    </div>
  );
};

export default Hourly;

在 Codesandbox 上,有时它不起作用,所以我要做的是注释所有DailyHourly组件,等待 2 秒以重新加载 Codesandbox,然后取消注释它们,通常它会起作用。

VSCode 并非如此。它会说currentWeatherOne.weather 未定义,这意味着currentWeatherOne尝试访问尚未存在的信息。我不明白,这不是使用承诺的全部意义吗?使用异步、等待等?让它等待返回结果,然后显示它?不管是什么原因,为什么它适用于代码和框而不是 VSCode?

真的很想得到反馈和帮助。谢谢你们!

4

1 回答 1

0

currentWeatherOne 最初设置为空对象{},您正尝试currentWeatherOne.weather[0].icon在返回部分访问。由于weather尚不可用currentWeatherOne,因此您收到此错误。

UseEffect 在第一次渲染后调用,因此您getWeather在初始渲染后调用获取天气信息。直到那个时候,currentWeatherOne只是空的对象。

已在此处解决了问题 - https://codesandbox.io/s/tender-wood-b4kuh

希望这可以帮助。

于 2020-02-25T08:31:44.673 回答