React组件间传值方案:搜索输入传递至天气数据组件
React组件间传值实现天气搜索功能解决方案
我有两个React组件:Search组件提供搜索输入框供用户输入城市名称;Maindata组件负责调用天气API并展示气温、风速等天气数据。需要实现将用户在Search组件中输入的城市名称传递至Maindata组件的API调用逻辑,从而渲染对应城市的天气数据。
核心解决方案:使用React的状态提升机制,将共享状态(选中的城市)提升到两个组件的共同父组件App.js中,通过props实现组件间的数据传递和回调。
1. 修改App.js(父组件)
将城市状态提升到App组件,同时给子组件传递必要的props:
import "./App.css"; import Maindata from "./Components/Maindata"; import Search from "./Components/Search"; import { useState } from "react"; function App() { // 保存用户选择的城市名称 const [selectedCity, setSelectedCity] = useState("mansehra"); // 接收Search组件传递的城市名称 const handleCitySubmit = (city) => { setSelectedCity(city); }; return ( <div className="mainpage"> <div className="searchComp"> {/* 给Search组件传递回调函数,用于接收输入的城市 */} <Search onSubmit={handleCitySubmit} /> </div> <div className="details"> {/* 给Maindata组件传递选中的城市 */} <Maindata city={selectedCity} /> </div> </div> ); } export default App;
2. 修改Search组件(子组件)
移除不必要的逻辑,通过props接收父组件的回调函数,提交时将输入的城市传递给父组件:
import React, { useState } from "react"; import "../Componentstyle/search.css"; export default function Search({ onSubmit }) { const [location, setLocation] = useState(""); const handleSubmit = () => { // 确保输入不为空时再触发回调 if (location.trim()) { onSubmit(location.trim()); } }; return ( <div className="main"> <nav className="istclass"> <form className="form" onSubmit={(e) => e.preventDefault()}> <div className="search"> <input value={location} placeholder="search city" className="searchbox" onChange={(e) => setLocation(e.target.value)} /> <button className="nd" type="button" onClick={handleSubmit}> Submit </button> </div> </form> </nav> </div> ); }
修复了原代码中
handlesubmit函数的错误(原代码中event.target.value获取的是按钮的值,而非输入框内容),改为直接使用组件内部的location状态值。
3. 修改Maindata组件(子组件)
通过props接收城市名称,将城市作为useEffect的依赖项,实现城市变化时自动调用API更新数据:
import React, { useState, useEffect } from "react"; import "../Componentstyle/Main.css"; export default function Maindata({ city }) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const fetchWeather = async () => { if (!city) return; setLoading(true); setError(null); const key = "XYZ"; // 替换为你的实际API密钥 try { const response = await fetch( `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${key}&units=metric&formatted=0` ); if (!response.ok) { throw new Error("城市未找到或API请求失败"); } const actualData = await response.json(); setData(actualData); } catch (err) { setError(err.message); } finally { setLoading(false); } }; useEffect(() => { fetchWeather(); }, [city]); // 当city变化时重新调用API if (loading) { return <div>Loading...</div>; } if (error) { return <div>错误:{error}</div>; } if (!data) { return <div>请输入城市名称</div>; } const link = `http://openweathermap.org/img/w/${data.weather[0].icon}.png`; return ( <div className="maindata"> <div className="city">{data.name}</div> <div className="temp">{data.main.temp} °C</div> <div className="icon"> <img src={link} alt={data.weather[0].description} /> </div> <div className="feel">体感温度 {data.main.feels_like} °C</div> <div className="wind">风速 {data.wind.speed} Km/hr</div> <div className="cloudy">{data.weather[0].main}</div> <div className="humidity">湿度 {data.main.humidity}%</div> <div className="sunrise"> 日出时间:{new Date(data.sys.sunrise * 1000).toLocaleString()} </div> <div className="sunset"> 日落时间:{new Date(data.sys.sunset * 1000).toLocaleString()} </div> </div> ); }
优化说明:
- 添加了加载状态和错误状态的处理,提升用户体验
- 将原有的
async/await和.then()混合写法统一为async/await,代码更清晰- 优化了日期显示格式为本地时间,更符合用户习惯
- 增加了API请求失败的错误处理,避免页面崩溃
内容的提问来源于stack exchange,提问作者Ahsan Khalid
相关产品推荐
相关产品推荐

