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

React跨组件通信问题:Navbar搜城市后更新Offers组件数据

解决方案:用Redux实现跨组件状态共享

看起来你已经在使用Redux了,那用它来管理选中城市这个共享状态就是最适合的方案——毕竟Navbar和Anuncios是独立组件,Redux的全局store刚好能解决这种跨组件通信的问题。下面一步步帮你改代码:


第一步:完善Navbar组件,获取搜索输入并更新Redux状态

首先要给Navbar加个状态存输入框的值,提交时先通过searchCidadesRequestID获取城市ID,再把ID存入Redux store:

class NavigationBar extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      cityInput: '' // 新增:存储输入框的城市名称
    };
    this.cityoffer = this.cityoffer.bind(this);
    this.handleInputChange = this.handleInputChange.bind(this);
  }

  // 实时更新输入框状态
  handleInputChange(e) {
    this.setState({ cityInput: e.target.value });
  }

  async cityoffer(e) {
    e.preventDefault();
    const { cityInput } = this.state;
    if (!cityInput.trim()) return; // 空输入直接返回,避免无效请求

    try {
      // 调用API获取城市ID(假设searchCidadesRequestID是异步action,返回城市ID)
      const cityId = await this.props.searchCidadesRequestID(cityInput);
      // 触发action,把城市ID存入Redux store
      this.props.setSelectedCity(cityId);
      // 跳转到首页展示筛选后的结果
      this.props.history.push("/home");
    } catch (err) {
      console.error('获取城市信息失败:', err);
      // 这里可以用FlashMessages提示用户错误,比如城市不存在
    }
  }

  render(){
    const { isAuthenticated } = this.props.auth;
    const userLinks = (
      <form className="form-inline my-2 my-lg-0 ml-auto" onSubmit={this.cityoffer}>
        <input 
          className="form-control mr-sm-2" 
          type="search" 
          placeholder="Cidade" 
          aria-label="Search"
          value={this.state.cityInput} // 绑定状态到输入框
          onChange={this.handleInputChange} // 绑定输入事件
        />
        <button className="btn btn-outline-success my-2 my-sm-0" type="submit">Procurar</button>
      </form>
    );
    // 剩下的guestLinks和render内容保持不变
    const guestLinks = (
      <ul className="navbar-nav ml-auto">
        <li className="nav-item">
          <Link to="/login" className="nav-link">Entrar</Link>
        </li>
        <li className="nav-item">
          <Link to="/signup" className="nav-link">Registrar</Link>
        </li>
      </ul>
    );

    return (
      <nav className="navbar navbar-expand-lg navbar-dark bg-dark">
        <button className="navbar-brand brandbutton" onClick={this.brand}><img src={imglogo} className="imagemNav" alt="logo"/></button>
        <button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
          <span className="navbar-toggler-icon"></span>
        </button>
        <div className="navbar-collapse collapse w-100 order-3 dual-collapse2" id="navbarNavAltMarkup">
          { isAuthenticated ? userLinks : guestLinks }
        </div>
      </nav>
    );
  }
}

// 更新propTypes,新增需要的action
NavigationBar.propTypes = {
  auth: PropTypes.object.isRequired,
  logout: PropTypes.func.isRequired,
  searchCidadesRequestID: PropTypes.func.isRequired,
  setSelectedCity: PropTypes.func.isRequired
}

function mapStateToProps(state) {
  return { auth: state.auth };
}

// 把新增的action加到connect里
export default withRouter(connect(mapStateToProps, { logout, searchCidadesRequestID, setSelectedCity })(NavigationBar));

第二步:创建Redux的Action和Reducer管理选中城市

你需要新增一套action和reducer来存储选中的城市ID:

创建Action(actions/cityActions.js)

export const SET_SELECTED_CITY = 'SET_SELECTED_CITY';

// 更新选中城市的action
export const setSelectedCity = (cityId) => ({
  type: SET_SELECTED_CITY,
  payload: cityId
});

创建Reducer(reducers/cityReducer.js)

import { SET_SELECTED_CITY } from '../actions/cityActions';

// 初始值和Anuncios组件的默认城市保持一致
const initialState = {
  selectedCity: 2958
};

export default function cityReducer(state = initialState, action) {
  switch(action.type) {
    case SET_SELECTED_CITY:
      return {
        ...state,
        selectedCity: action.payload
      };
    default:
      return state;
  }
}

把Reducer添加到Root Reducer

在你的根reducer里(比如reducers/index.js),把cityReducer合并进去:

import { combineReducers } from 'redux';
import authReducer from './authReducer';
import anunciosReducer from './anunciosReducer';
import cityReducer from './cityReducer'; // 导入新的reducer

export default combineReducers({
  auth: authReducer,
  anuncios: anunciosReducer,
  city: cityReducer // 新增这一行
});

第三步:修改Anuncios组件,监听Redux状态变化

把Anuncios组件改成从Redux store获取选中城市,并且当城市变化时自动重新请求数据:

class Anuncios extends React.Component {
  componentDidMount() {
    // 组件挂载时,用store里的初始城市请求数据
    this.props.fetchAnuncios(this.props.selectedCity);
  }

  // 用componentDidUpdate代替已废弃的componentWillReceiveProps
  componentDidUpdate(prevProps) {
    // 当选中城市变化时,重新请求数据
    if (prevProps.selectedCity !== this.props.selectedCity) {
      this.props.fetchAnuncios(this.props.selectedCity);
    }
  }

  render() {
    return (
      <div className="pagemargin">
        <AnunciosList anuncios={this.props.anuncios}/>
      </div>
    );
  }
}

Anuncios.propTypes = {
  anuncios: PropTypes.array.isRequired,
  fetchAnuncios: PropTypes.func.isRequired,
  selectedCity: PropTypes.number.isRequired // 新增prop类型
}

function mapStateToProps(state) {
  return {
    anuncios: state.anuncios,
    selectedCity: state.city.selectedCity // 从store里获取选中的城市ID
  }
}

export default connect(mapStateToProps, {fetchAnuncios, searchCidadesRequestID})(Anuncios);

第四步:确保Home组件包含Anuncios

因为你提交后跳转到/home,所以Home组件需要渲染Anuncios,比如:

// Home.js
import React from 'react';
import Anuncios from './path/to/Anuncios'; // 替换成你的实际路径

class Home extends React.Component {
  render() {
    return (
      <div className="home-container">
        {/* 其他Home页面的内容 */}
        <Anuncios />
      </div>
    );
  }
}

export default Home;

补充:异步Action的注意事项

如果你的searchCidadesRequestID是异步action(比如用了redux-thunk),要确保它返回Promise,这样才能用await获取城市ID。示例实现:

// 示例异步action
export const searchCidadesRequestID = (cityName) => async (dispatch) => {
  try {
    const response = await fetch(`/api/cidades?name=${encodeURIComponent(cityName)}`);
    const cities = await response.json();
    
    if (cities.length === 0) {
      throw new Error('城市不存在');
    }
    
    // 返回第一个匹配的城市ID
    return cities[0].id;
  } catch (error) {
    throw error; // 抛出错误让Navbar处理
  }
};

这样一套流程下来,当你在Navbar搜索城市提交后,Redux store会更新选中的城市ID,Anuncios组件监听到这个变化就会自动调用API获取对应城市的Offers,完美解决跨组件通信的问题~

内容的提问来源于stack exchange,提问作者AND4011002849

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:45:24