React中如何展示天气API数据?是否需用useEffect或事件处理器?
问题解答:React中展示天气API数据的实现方案
你的核心问题是如何展示天气API的数据,以及选择useEffect还是事件处理器。答案很明确:用事件处理器更适合你的场景,因为获取天气是用户点击搜索按钮的主动操作,而useEffect更适合依赖项变化时自动触发的场景(比如页面加载时自动获取默认城市天气)。
下面是具体的实现步骤和修改后的代码:
步骤1:添加天气数据状态
首先需要新增一个状态来存储获取到的天气数据,因为你现在的getWeather函数只是返回数据,没有保存到组件状态中:
const [weather, setWeather] = useState<Forecast | null>(null);
步骤2:修改提交逻辑,保存天气数据
在onSubmit函数中,调用getWeather后把返回的数据存入状态:
const onSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!town) return; // 获取天气数据并更新状态 const weatherData = await getWeather(town); setWeather(weatherData); setSearch(""); setScores([]); };
步骤3:渲染天气数据
在组件的返回部分,添加天气数据的展示区域,比如在form之后:
{weather && ( <div className="weather-card"> <h3>{weather.name}</h3> <p>温度:{weather.main.temp}°C</p> <p>天气:{weather.weather[0].description}</p> <p>湿度:{weather.main.humidity}%</p> </div> )}
完整修改后的代码
import { useEffect, useState } from "react"; import { Town, Forecast } from "./type"; const WEATHER_API_KEY = "API KEY HERE"; export default function SearchCity(): JSX.Element { const [search, setSearch] = useState<string>(""); const [town, setTown] = useState<Town | null>(null); const [scores, setScores] = useState<Town[]>([]); // 新增天气数据状态 const [weather, setWeather] = useState<Forecast | null>(null); const onSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!town) return; // 获取天气并更新状态 const weatherData = await getWeather(town); setWeather(weatherData); setSearch(""); setScores([]); }; const getLocations = async (value: string): Promise<Town[]> => { const url = `http://api.openweathermap.org/geo/1.0/direct?q=${value}&limit=3&appid=${WEATHER_API_KEY}`; const res = await fetch(url); return await res.json(); }; const onInputChange = async (e: React.ChangeEvent<HTMLInputElement>) => { const { value } = e.target; setSearch(value); if (!value) return; const locations = await getLocations(value); setScores(locations); }; const getWeather = async (town: Town): Promise<Forecast> => { const url = `https://api.openweathermap.org/data/2.5/weather?lat=${town.lat}&lon=${town.lon}&units=metric&appid=${WEATHER_API_KEY}`; const res = await fetch(url); return await res.json(); }; const onScoreSelect = (score: Town) => { setTown(score); }; useEffect(() => { if (town) { setSearch(town.name); setScores([]); } }, [town]); return ( <div className="search-container"> <form onSubmit={onSubmit}> <input className="input" value={search} onChange={onInputChange} type="text" placeholder="Choose a city" /> <button className="submit" type="submit"> Search </button> <ul className="list"> {scores.map((score: Town, index: number) => ( <li key={index}> <button className="score-btn" onClick={() => onScoreSelect(score)} > {score.name} </button> </li> ))} </ul> </form> {/* 渲染天气数据 */} {weather && ( <div className="weather-card"> <h2>{weather.name}</h2> <div className="weather-main"> <img src={`https://openweathermap.org/img/wn/${weather.weather[0].icon}@2x.png`} alt={weather.weather[0].description} /> <p>{Math.round(weather.main.temp)}°C</p> </div> <p className="weather-desc">{weather.weather[0].description}</p> <div className="weather-details"> <p>湿度: {weather.main.humidity}%</p> <p>风速: {weather.wind.speed} m/s</p> </div> </div> )} </div> ); }
关于useEffect的补充说明
如果你的需求变成用户选择城市后自动加载天气,不需要点击搜索按钮,那可以用useEffect监听town的变化:
useEffect(() => { if (town) { const fetchWeather = async () => { const data = await getWeather(town); setWeather(data); }; fetchWeather(); } }, [town]);
这种场景下useEffect就很合适,但回到你的原需求,用户点击搜索才触发,所以事件处理器是更贴合的选择。
内容的提问来源于stack exchange,提问作者MrBiedny
相关产品推荐
相关产品推荐

