首页 >web前端 >js教程 >如何在 React 中构建天气应用

如何在 React 中构建天气应用

Patricia Arquette
Patricia Arquette原创
2024-10-21 22:38:30918浏览

如果您想掌握关键的 Web 开发技能,例如使用 API、获取数据以及 React 中的 async 和 wait 等异步函数,那么构建天气应用程序是最好的学习方法。

这也是一个有趣的项目,因为您可以看到实时天气和天气预报。

在本教程中,我们将使用 React 构建一个功能齐全的天气应用程序,该应用程序将显示任何城市的天气以及该城市 5 天的天气预报。

除了知道明天会不会下雨?,你还会学到这些概念:

  • 如何与外部API通信
  • React 中的数据获取
  • 异步操作以及async和await的奥秘。

在本教程结束时,您将构建一个如下所示的应用程序:

How to Build a Weather App in React

如果您需要温习 React 基础知识,请阅读本教程:

React 入门:初学者完整指南

让我们开始吧。

开发环境

Vite 是一款旨在提供更快、更高效的开发体验的构建工具。它配备了一个开发服务器,可增强本机 ES 模块,具有极快的热模块替换 (HMR) 等功能,以及一个利用 Rollup 将代码捆绑到高度优化的静态资产以进行生产的构建命令。

在您的终端中,发出此命令,这将创建一个名为react-weather的新应用程序

npm create vite@latest react-weather

下一步,选择 Reat 作为框架,选择 JavaScript 作为变体。

How to Build a Weather App in React

Vite 创建应用程序后,cd 进入react-weather 文件夹并运行 npm install 和 npm run 命令。

 cd react-weather
 npm install
 npm run dev

现在您的应用程序应该运行在 http://localhost:5173/

构建界面

我们将首先在 app.jsx 文件中构建 UI,并删除返回片段中的所有内容。您的 app.jsx 现在应该如下所示:

import { useState } from 'react'
import './App.css'

function App() {

  return (
    <>

    </>
  )
}

export default App

UI 将分为 3 个部分。 

  • 标题:这将显示城市、温度和天气状况
  • 天气详情部分:此部分将显示湿度和风速
  • 天气预报部分:这将显示每个城市未来 5 天的天气预报。每天都会显示气温和天气状况(阴天、晴天、阴天)等。

在 return 语句中,我们首先添加一个包装 div。此 div 元素将包含所有部分:

npm create vite@latest react-weather

在包装器内,添加带有

的标头显示城市,一个

元素表示温度,另一个/>元素表示整体天气状况。
 cd react-weather
 npm install
 npm run dev

在详细信息部分,我们希望连续显示湿度和风速,因此每个数据都将位于其 div 元素中。

import { useState } from 'react'
import './App.css'

function App() {

  return (
    <>

    </>
  )
}

export default App

最后,预测部分每天都会有一个标题和几个列表项。对于列表项,我们先暂时显示两天。

import { useState } from 'react'
import './App.css'

function App() {

  return (
     <div className="wrapper">

      </div>
  )
}

export default App

到目前为止,我们的应用程序现在看起来像这样:

How to Build a Weather App in React

使用 CSS 设计样式

为了让我们的界面美观,让我们添加一些样式,我们将使用CSS。在 main.jsx 文件中,我们已经有了这个导入,它导入了我们应用程序的所有全局样式

import { useState } from "react";
import "./App.css";

function App() {
  return (
    <div className="wrapper">
      <div className="header">
        <h1 className="city">London</h1>
        <p className="temperature">60°F</p>
        <p className="condition">Cloudy</p>
      </div>
    </div>
  );
}

export default App;

让我们首先使用 flex 来设计身体的样式。

export default App;

import { useState } from "react";
import "./App.css";

function App() {
  return (
    <div className="wrapper">
      <div className="header">
        <h1 className="city">London</h1>
        <p className="temperature">60°F</p>
        <p className="condition">Cloudy</p>
      </div>
      <div className="weather-details">
        <div>
          <p>Humidity</p>
          <p> 60%</p>
        </div>
        <div>
          <p>Wind Speed</p>
          <p>7 mph</p>
        </div>
      </div>
    </div>
  );
}

在这里,我们设置了 justify-items:center 和 justify-content:center 以确保所有内容水平和垂直居中。

对于包装器,我们添加不同的背景颜色、最小宽度、圆角边框和框阴影,以及所有边的边距。

export default App;

import { useState } from "react";
import "./App.css";

function App() {
  return (
    <div className="wrapper">
      <div className="header">
        <h1 className="city">London</h1>
        <p className="temperature">60°F</p>
        <p className="condition">Cloudy</p>
      </div>
      <div className="weather-details">
        <div>
          <p>Humidity</p>
          <p> 60%</p>
        </div>
        <div>
          <p>Wind Speed</p>
          <p>7 mph</p>
        </div>
      </div>
      <div className="forecast">
        <h2 className="forecast-header">5-Day Forecast</h2>
        <div className="forecast-days">
          <div className="forecast-day">
            <p>Monday</p>
            <p>Cloudy</p>
            <p>12°F</p>
          </div>
          <div className="forecast-day">
            <p>Monday</p>
            <p>Cloudy</p>
            <p>12°F</p>
          </div>
        </div>
      </div>
    </div>
  );
}

为城市名称和温度元素添加更大的字体并使其加粗。标题元素的整体样式如下所示:

import './index.css'

为了确保天气详细信息部分中的元素(即湿度和风速)在同一行上对齐,请使用 display: flex 和 justify-content: space- Between ;这些是天气细节及其元素的样式:

body {
  min-height: 100vh;
  background: linear-gradient(to bottom right, #60a5fa, #3b82f6);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  font-family: Arial, sans-serif;
}

最后,对于天气预报部分,添加以下样式:

.wrapper {
  background: rgba(255, 255, 255, 0.2);
  border-radius: 1.5rem;
  padding: 2rem;
  min-width: 400px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

现在我们的应用程序如下所示:

How to Build a Weather App in React

获取实时天气数据

到目前为止,我们使用的是占位符数据,为了获取实时天气信息,我们将使用 openweather API。前往 https://openweathermap.org/api 并获取免费的 API 密钥。

定义 API_KEY。

 

.city {
  font-size: 2.5rem;
  font-weight: bold;
}
.temperature {
  font-size: 3.5rem;
  font-weight: bold;
}

.condition {
  font-size: 1.25rem;

}

在生产环境中,您应该在 .env 文件中添加 API 密钥等敏感数据。

使用状态存储天气数据

在 React 中,状态是一个至关重要的概念,因为它允许组件管理和响应动态数据。当您从 API 获取数据时,您需要一种在组件内存储和操作该数据的方法。

这就是状态发挥作用的地方。

React 组件中所有可能随时间变化的内容都由状态管理。当状态发生变化时,React 组件将重新渲染并反映新的变化。

例如,在我们的天气应用中,我们想要获取特定城市的当前天气信息并将其存储在该州。

为此,我们将使用 useState 挂钩。这个钩子的语法如下所示:

npm create vite@latest react-weather
  • value 是当前状态值。
  • setValue 是一个允许您更新状态的函数。
  • initialValue 是状态开始的值(可以是数字、字符串、对象,甚至数组)。

在App功能顶部定义天气数据状态。初始值为 null

 cd react-weather
 npm install
 npm run dev
  • weatherData 将存储天气详细信息
  • setWeather 将更新天气详细信息

定义城市的状态并将城市名称的初始状态变量设置为伦敦

import { useState } from 'react'
import './App.css'

function App() {

  return (
    <>

    </>
  )
}

export default App

使用 useEffect Hook 获取数据

React 默认情况下无法处理副作用。副作用是发生在 Reacts 控制之外的操作,例如异步操作、本地存储等。 c .

由于 React 组件在挂载时呈现,因此在此阶段发出 API 请求将无法访问数据,因为获取请求需要时间才能完成。

在这种情况下,React 使用 useEffect 钩子来执行副作用。 useEffect 挂钩将函数作为第一个参数和依赖项数组。它的语法如下所示:

import { useState } from 'react'
import './App.css'

function App() {

  return (
     <div className="wrapper">

      </div>
  )
}

export default App

useEffect 挂钩中的依赖项数组包含确定效果何时运行的变量。例如,在我们的例子中,useEffect 应该在天气数据发生变化时运行,而不是在每次渲染时运行。

在 useEffect 中,创建一个异步函数,该函数将从开放天气 API 获取特定城市的天气。既然是异步操作,我们的函数也应该是异步的。

函数以城市名称为参数

import { useState } from "react";
import "./App.css";

function App() {
  return (
    <div className="wrapper">
      <div className="header">
        <h1 className="city">London</h1>
        <p className="temperature">60°F</p>
        <p className="condition">Cloudy</p>
      </div>
    </div>
  );
}

export default App;

获取数据后,使用 setWeatherData setter 函数用响应数据更新状态。确保将代码包装在 try-catch 块中以处理任何潜在的错误。

export default App;

import { useState } from "react";
import "./App.css";

function App() {
  return (
    <div className="wrapper">
      <div className="header">
        <h1 className="city">London</h1>
        <p className="temperature">60°F</p>
        <p className="condition">Cloudy</p>
      </div>
      <div className="weather-details">
        <div>
          <p>Humidity</p>
          <p> 60%</p>
        </div>
        <div>
          <p>Wind Speed</p>
          <p>7 mph</p>
        </div>
      </div>
    </div>
  );
}

为了在挂载时获取数据,我们需要调用 useEffect 中的获取天气数据函数。

调用该函数时,我们将传递当前城市的值作为参数。这将确保当应用程序第一次安装时,我们已经有一些数据可以显示城市状态中指定的值。

export default App;

import { useState } from "react";
import "./App.css";

function App() {
  return (
    <div className="wrapper">
      <div className="header">
        <h1 className="city">London</h1>
        <p className="temperature">60°F</p>
        <p className="condition">Cloudy</p>
      </div>
      <div className="weather-details">
        <div>
          <p>Humidity</p>
          <p> 60%</p>
        </div>
        <div>
          <p>Wind Speed</p>
          <p>7 mph</p>
        </div>
      </div>
      <div className="forecast">
        <h2 className="forecast-header">5-Day Forecast</h2>
        <div className="forecast-days">
          <div className="forecast-day">
            <p>Monday</p>
            <p>Cloudy</p>
            <p>12°F</p>
          </div>
          <div className="forecast-day">
            <p>Monday</p>
            <p>Cloudy</p>
            <p>12°F</p>
          </div>
        </div>
      </div>
    </div>
  );
}

如果您使用开发者工具检查日志,您将看到我们在每次渲染时发出多个 API 请求。

这是一个非常昂贵的操作,为了防止每次渲染时都获取数据,我们需要为 useEffect 提供一些依赖。这些依赖项将确定何时对开放天气 API 进行 API 调用。

因此,让我们在依赖数组中添加 city,以确保 API 调用只会在第一次挂载或 city 值发生变化时进行。

npm create vite@latest react-weather

当我们记录数据时,我们会得到一个包含伦敦市天气详细信息的对象。

 cd react-weather
 npm install
 npm run dev

现在让我们使用 JSX 将天气详细信息注入到元素中。

import { useState } from 'react'
import './App.css'

function App() {

  return (
    <>

    </>
  )
}

export default App

在 JavaScript 中,表达式条件 && 用于 React 组件内的条件渲染。

&& 运算符检查两个条件,仅当两个条件都为 true 时才返回 true。在我们的例子中,如果weatherData存在,则将渲染指定的数据属性。

如果weatherData为null(或未定义),则不会渲染元素,从而防止尝试访问null的属性时可能发生的任何错误。

在 React 中获取并显示天气预报

为了获取天气预报,我们将使用此 API 在同一个 useEffect Hook 中执行另一个获取请求 https://api.openweathermap.org/data/2.5/forecast?q=${CITY}&appid=${API_KEY} &单位=英制

首先,创建一个预测状态来存储预测数据,并将初始值初始化为空数组。

import { useState } from 'react'
import './App.css'

function App() {

  return (
     <div className="wrapper">

      </div>
  )
}

export default App

在 fetchWeatherData 函数内,向上述 API 发出获取请求,并将预测状态设置为响应数据。

import { useState } from "react";
import "./App.css";

function App() {
  return (
    <div className="wrapper">
      <div className="header">
        <h1 className="city">London</h1>
        <p className="temperature">60°F</p>
        <p className="condition">Cloudy</p>
      </div>
    </div>
  );
}

export default App;

预测API通常会在接下来的5天内每3小时返回一次预测,结果为40个数据点,这是截断的输出。

export default App;

import { useState } from "react";
import "./App.css";

function App() {
  return (
    <div className="wrapper">
      <div className="header">
        <h1 className="city">London</h1>
        <p className="temperature">60°F</p>
        <p className="condition">Cloudy</p>
      </div>
      <div className="weather-details">
        <div>
          <p>Humidity</p>
          <p> 60%</p>
        </div>
        <div>
          <p>Wind Speed</p>
          <p>7 mph</p>
        </div>
      </div>
    </div>
  );
}

变量 dt 是一个时间戳,因此如果我们想使用 toLocaleDateString() 方法将其转换为人类可读的时间。

export default App;

import { useState } from "react";
import "./App.css";

function App() {
  return (
    <div className="wrapper">
      <div className="header">
        <h1 className="city">London</h1>
        <p className="temperature">60°F</p>
        <p className="condition">Cloudy</p>
      </div>
      <div className="weather-details">
        <div>
          <p>Humidity</p>
          <p> 60%</p>
        </div>
        <div>
          <p>Wind Speed</p>
          <p>7 mph</p>
        </div>
      </div>
      <div className="forecast">
        <h2 className="forecast-header">5-Day Forecast</h2>
        <div className="forecast-days">
          <div className="forecast-day">
            <p>Monday</p>
            <p>Cloudy</p>
            <p>12°F</p>
          </div>
          <div className="forecast-day">
            <p>Monday</p>
            <p>Cloudy</p>
            <p>12°F</p>
          </div>
        </div>
      </div>
    </div>
  );
}

此时间戳的输出是 sat

所以对于40个预测项的数组,我们使用了filter函数根据给定的(item,index)=>进行过滤索引 % 8 === 0 条件。

(项目,索引)=> index % 8 === 0:此条件的意思是:“仅保留索引可被 8 整除的预测。”由于每 3 小时预报一次,因此每 8 项代表每天 1 次预报(3 小时 × 8 = 24 小时)。

例如,假设索引范围为 0-39,则每第 8 个索引都会添加到 dailyForecast 数组中。我们总共将拥有 5 个天气数据实例。

每个天气预报数据点如下所示:

import './index.css'

由于我们有 5 个实例,因此我们将使用 map() 方法来迭代并显示每天的天气预报。

更新预测部分如下:

body {
  min-height: 100vh;
  background: linear-gradient(to bottom right, #60a5fa, #3b82f6);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  font-family: Arial, sans-serif;
}

在这里,我们还检查预测数组是否包含数据,以确保我们不会循环遍历空数组,从而导致弹出错误。

检查预测数据后,我们映射预测数组并注入每天的以下数据。

  • 一周中的某一天
  • 天气图标
  • 温度

现在我们的应用程序如下所示:

How to Build a Weather App in React

获取自定义天气信息

我们的应用程序看起来很棒,但我们仍然无法获取动态数据。让我们在顶部添加一个搜索表单,以允许用户获取有关任何城市的信息。

但首先,我们需要输入字段的状态。以空字符串作为初始值声明状态。

npm create vite@latest react-weather

创建表单,将输入绑定到 searchInput 状态,并添加 onChange 事件,该事件将在用户键入新城市时更新 searchInput 值。

 cd react-weather
 npm install
 npm run dev

以下是表单的样式。

import { useState } from 'react'
import './App.css'

function App() {

  return (
    <>

    </>
  )
}

export default App

由于我们需要在提交表单时调用weatherData函数,因此我们会将函数定义移到useEffect钩子之外,但仍然调用它,因为应用程序需要在安装时显示初始城市值的一些数据。

import { useState } from 'react'
import './App.css'

function App() {

  return (
     <div className="wrapper">

      </div>
  )
}

export default App

提交表格后获取天气数据

用户使用搜索表单搜索城市后,我们需要调用另一个函数,该函数将调用新城市的 fetchWeatherData 并将 WeatherData 状态更新为新城市的天气信息。

向表单添加 onSubmitevent 并引用函数,如下所示。

import { useState } from "react";
import "./App.css";

function App() {
  return (
    <div className="wrapper">
      <div className="header">
        <h1 className="city">London</h1>
        <p className="temperature">60°F</p>
        <p className="condition">Cloudy</p>
      </div>
    </div>
  );
}

export default App;

提交表单后,它将获取新城市的天气信息。

export default App;

import { useState } from "react";
import "./App.css";

function App() {
  return (
    <div className="wrapper">
      <div className="header">
        <h1 className="city">London</h1>
        <p className="temperature">60°F</p>
        <p className="condition">Cloudy</p>
      </div>
      <div className="weather-details">
        <div>
          <p>Humidity</p>
          <p> 60%</p>
        </div>
        <div>
          <p>Wind Speed</p>
          <p>7 mph</p>
        </div>
      </div>
    </div>
  );
}

由于 fetchWeatherData 函数已经使用新数据更新了weatherData 状态的新状态,因此我们仅调用该函数并从用户 (searchInput) 传递新城市的值。

错误处理

从 API 获取数据时,可能会出现各种问题。例如,在我们的例子中,天气 API 可能会关闭,或者我们可能有无效的 API 密钥,或者我们可能已经耗尽了每日 API 限制。

在这种情况下,我们需要添加适当的错误处理机制,这样用户就不会遇到服务器错误。

例如,当应用程序第一次加载时,forecast 数组将为空,weatherData 将为 null。为了确保良好的用户体验,让我们添加错误和加载状态。

export default App;

import { useState } from "react";
import "./App.css";

function App() {
  return (
    <div className="wrapper">
      <div className="header">
        <h1 className="city">London</h1>
        <p className="temperature">60°F</p>
        <p className="condition">Cloudy</p>
      </div>
      <div className="weather-details">
        <div>
          <p>Humidity</p>
          <p> 60%</p>
        </div>
        <div>
          <p>Wind Speed</p>
          <p>7 mph</p>
        </div>
      </div>
      <div className="forecast">
        <h2 className="forecast-header">5-Day Forecast</h2>
        <div className="forecast-days">
          <div className="forecast-day">
            <p>Monday</p>
            <p>Cloudy</p>
            <p>12°F</p>
          </div>
          <div className="forecast-day">
            <p>Monday</p>
            <p>Cloudy</p>
            <p>12°F</p>
          </div>
        </div>
      </div>
    </div>
  );
}

在 fetchWeatherData 函数中,在任何获取发生之前,设置错误和加载的初始状态

import './index.css'

在 catch 块中,让我们将错误状态设置为用户友好的消息

body {
  min-height: 100vh;
  background: linear-gradient(to bottom right, #60a5fa, #3b82f6);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  font-family: Arial, sans-serif;
}

在 JavaScript 中,try catch 块中的 finally 子句非常适合清理。无论 API 操作的结果如何,我们都希望删除加载状态。

.wrapper {
  background: rgba(255, 255, 255, 0.2);
  border-radius: 1.5rem;
  padding: 2rem;
  min-width: 400px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

为了确保错误和加载状态反映在 UI 中,请在 return 语句之前添加此代码

npm create vite@latest react-weather

要在发生错误时显示错误消息,请添加此

;表单后的标签。
 cd react-weather
 npm install
 npm run dev

此条件确保如果发生错误,将显示存储在状态中的错误消息。

这是处于加载状态的应用程序。

How to Build a Weather App in React

这是发生错误时的输出。

How to Build a Weather App in React

结论

本教程到此结束。您可以在这里找到源代码。

如果您发现本教程有点具有挑战性,您可能需要温习一下 React 基础知识。

获取我的免费 React 指南并升级。

快乐编码。

以上是如何在 React 中构建天气应用的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn