You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:53:52