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
相关产品推荐
相关产品推荐

