如何在React Router中向独立搜索组件传递state?
实现React Router跳转+组件间状态传递的方案
我来帮你一步步完成把搜索功能迁移到独立组件并通过React Router访问的需求,主要分为组件拆分、路由配置和状态传递三个核心部分:
1. 第一步:创建独立的搜索组件(SearchPage)
首先新建一个SearchPage.js文件,把原App组件里的搜索表单、提交逻辑移过来。这个组件负责处理搜索输入和提交操作,我们会把App里的getWeather方法通过props传进来,这样就能更新App的全局状态了:
import React, { Component } from 'react'; import { Button } from 'react-bootstrap'; class SearchPage extends Component { // 组件内部管理输入框状态(可选,但更符合组件独立性) state = { cityInput: '' }; handleInputChange = (e) => { this.setState({ cityInput: e.target.value }); }; handleSubmit = (e) => { e.preventDefault(); const { cityInput } = this.state; if (!cityInput.trim()) { alert('请输入城市名称'); return; } // 调用从App传递过来的getWeather方法,更新全局状态 e.target.city.value = cityInput; this.props.getWeather(e); }; render() { return ( <div className="container"> <div className="row"> <div id="city"> <div className="form-group mb-2"> <div className="form-group mx-sm-3 mb-2"> <form className="form-inline" onSubmit={this.handleSubmit}> <input type="text" name="city" className="form-control" value={this.state.cityInput} onChange={this.handleInputChange} placeholder="Input City..." /> <Button variant="primary" type="submit"> Get Weather </Button> </form> </div> </div> </div> </div> </div> ); } } export default SearchPage;
2. 第二步:重构App组件为路由容器
接下来修改你的App.js,把它改成路由的父容器,保留原有的状态和业务方法(比如getWeather、getDate),因为Weather组件需要依赖这些状态数据。然后配置React Router,添加搜索页面的路由:
import React, { Component } from 'react'; import './App.css'; import Weather from "./Weather.js"; import 'bootstrap/dist/css/bootstrap.min.css'; import { BrowserRouter as Router, Route, Link } from "react-router-dom"; import SearchPage from "./SearchPage.js"; // 导入新组件 const API_KEY = "2a41aeea56aabfb9ff1218730fc32426"; class App extends React.Component { state = { temperature: "", city: "", city2:"", country: "", msg: "", pressure: "", humidity: "", description: "", rain:"", main:"Drizzle", icon: "09d", error: "", date: "", month:"", lat:"", show: false, lng:"", year:"", clouds:"", showResults: false, moon_phase: "", moon_hour: "", moon_rise: "", moon_rises: "", moon_state: "", moon_set: "", moon_sets: "", sunset: "", sunsets: "", sunrise:"", sunrises:"" }; // 保留原有的getDate、getWeather、getTrail等方法不变 getDate() { var date = new Date().getDate(); var month = new Date().getMonth() + 1; var year = new Date().getFullYear(); this.setState({ date,year,month}); } componentDidMount() { this.getDate(); } getWeather = async (e) => { e.preventDefault(); this.setState({ showResults: true }); const city = e.target.city.value; const api_call = await fetch(`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${API_KEY}&units=metric`); const data = await api_call.json(); if (city) { this.setState({ temperature: data.main.temp, city: data.name, clouds:data.clouds.all, main: data.weather[0].main, icon: data.weather[0].icon, rain: data.rain, pressure: data.main.pressure, humidity: data.main.humidity, description: data.weather[0].description, error: "" }); } else { this.setState({ temperature: undefined, city: undefined, country: undefined, humidity: undefined, description: undefined, pressure:undefined, rain : undefined, error: "Please enter the values." }); } var clouds= data.clouds.all; if (clouds>30){ this.setState({ msg:" Poor conditions for stargazing!! " }) } else{ this.setState({ msg: " Good conditions for stargazing! no rain in forecast! " }) } } getTrail = async (e) => { e.preventDefault(); const city = e.target.city2.value; this.setState({ show: !this.state.show }); const country = e.target.country.value; const api_call = await fetch(`https://api.wunderground.com/api/b1049a092a7f69ea/astronomy/q/${country}/${city}.json`); const data = await api_call.json(); if (city) { this.setState({ moon_phase: data.moon_phase.ageOfMoon, moon_hour: data.moon_phase.hemisphere, moon_rise: data.moon_phase.moonrise.hour, moon_rises: data.moon_phase.moonrise.minute, moon_state: data.moon_phase.phaseofMoon, moon_set: data.moon_phase.moonset.hour, moon_sets: data.moon_phase.moonset.minute, sunset: data.sun_phase.sunset.hour, sunsets: data.sun_phase.sunset.minute, sunrise:data.sun_phase.sunrise.hour, sunrises:data.sun_phase.sunrise.minute }); } else { this.setState({ moon_phase: undefined, sunset: undefined }); } } render() { return ( <Router> <div> {/* 添加导航栏,方便在主页和搜索页切换 */} <nav className="navbar navbar-expand-lg navbar-light bg-light"> <Link className="navbar-brand" to="/">Weather Dashboard</Link> <div className="navbar-nav ml-auto"> <Link className="nav-link" to="/search">Search Weather</Link> </div> </nav> <br></br><br></br><br></br><br></br><br></br><br></br> {/* 路由配置:用render方法传递props给SearchPage */} <Route path="/search" render={(props) => ( <SearchPage {...props} getWeather={this.getWeather} /> )} /> {/* 主页:展示Weather组件和相关信息 */} <Route exact path="/" render={() => ( <div className="container"> <Weather className="fish" city={this.state.city} temperature={this.state.temperature} humidity={this.state.humidity} clouds={this.state.clouds} pressure={this.state.pressure} description={this.state.description} rain={this.state.rain} icon={this.state.icon} error={this.state.error} /> <h3> {this.state.msg} </h3> <div className="clearfix"> <div className="date"><p id="d"> {this.state.date}/{this.state.month}/{this.state.year}</p></div> </div> </div> )} /> </div> </Router> ); } } export default App;
3. 核心关键点说明
- 状态传递逻辑:我们把App的
getWeather方法通过props传给SearchPage,这样SearchPage提交表单时,就能调用这个方法更新App的全局状态,而Weather组件依然从App获取状态数据进行渲染,实现了状态的跨组件共享。 - 路由传参技巧:使用
Route的render属性而不是component属性,这样可以灵活地把父组件的方法、状态传递给路由组件。 - 组件独立性:SearchPage自己管理输入框的局部状态,避免了依赖父组件的冗余逻辑,让组件职责更清晰。
可选优化:简化getWeather方法
如果想让代码更简洁,可以把getWeather改成接收city参数,而不是事件对象:
// App.js中的getWeather修改为: getWeather = async (city) => { this.setState({ showResults: true }); const api_call = await fetch(`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${API_KEY}&units=metric`); const data = await api_call.json(); // 剩下的逻辑和原来一致,只是不需要处理e.preventDefault()了 } // SearchPage中的handleSubmit修改为: handleSubmit = (e) => { e.preventDefault(); const { cityInput } = this.state; if (!cityInput.trim()) { alert('请输入城市名称'); return; } this.props.getWeather(cityInput); }
这样代码会更易读,也符合函数式编程的最佳实践。
内容的提问来源于stack exchange,提问作者Leon Bogod
相关产品推荐
相关产品推荐

