React开发问题:如何实现Navbar组件与Home组件的搜索数据联动并仅在Home页渲染搜索结果
用Redux实现跨组件搜索状态共享(适配你的现有React项目)
既然你已经在使用Redux处理用户认证了,那直接用它来管理搜索状态就是最顺手的方案——完美解决非直接父子组件的状态传递问题,而且不用引入新的依赖。下面是一步步的实现指南:
1. 添加搜索相关的Redux模块
首先在你的redux目录下新建search文件夹,用来管理搜索状态:
redux/search/searchActions.js
export const SET_SEARCH_QUERY = 'SET_SEARCH_QUERY'; export const setSearchQuery = (query) => ({ type: SET_SEARCH_QUERY, payload: query });
redux/search/searchReducer.js
import { SET_SEARCH_QUERY } from './searchActions'; const initialState = { query: '' }; export const searchReducer = (state = initialState, action) => { switch (action.type) { case SET_SEARCH_QUERY: return { ...state, query: action.payload }; default: return state; } };
合并到根Reducer
找到你的根Reducer文件(比如redux/rootReducer.js),把搜索reducer加进去:
import { combineReducers } from 'redux'; import { authReducer } from './auth/authReducer'; import { searchReducer } from './search/searchReducer'; export const rootReducer = combineReducers({ auth: authReducer, search: searchReducer // 新增搜索状态模块 });
2. 修改NavbarComp组件,绑定搜索状态
更新NavbarComp.js,移除原来的input/setInput props,改用Redux来管理搜索值:
import { Layout } from "antd"; import { Link, useHistory } from "react-router-dom"; import Cookies from "js-cookie"; import { useDispatch, useSelector } from "react-redux"; import { logout } from "redux/auth/authActions"; import { setSearchQuery } from "redux/search/searchActions"; // 导入搜索action import { Nav, Navbar, Form, FormControl } from "react-bootstrap"; const { Header } = Layout; export const NavbarComp = () => { const history = useHistory(); const cookie = Cookies.get('token'); const dispatch = useDispatch(); const searchQuery = useSelector(state => state.search.query); // 获取当前搜索值 const logMeOut = (e) => { e.preventDefault(); dispatch(logout()); history.push('/'); }; const handleSearchChange = (e) => { dispatch(setSearchQuery(e.target.value)); // 实时更新Redux里的搜索状态 }; return ( <> <Navbar bg="light" expand="lg"> <Form className="d-flex"> <FormControl type="search" placeholder="Search" className="mr-2" aria-label="Search" value={searchQuery} // 绑定Redux状态到输入框 onChange={handleSearchChange} // 监听输入变化 /> </Form> {/* 保留你原有的Navbar其他内容(比如登录/注销按钮) */} </Navbar> </> ) }
3. 修改Home组件,移除本地输入框并复用搜索状态
更新Home.js,删掉本地的搜索状态,直接从Redux获取搜索值并过滤数据:
import React from 'react'; import { Link } from "react-router-dom"; import { useSelector } from 'react-redux'; import { v4 as uuid_v4 } from "uuid"; export const Home = () => { const connected = useSelector(state => state.auth.user); const searchQuery = useSelector(state => state.search.query); // 从Redux拿搜索值 const [flatsDefault, setFlatsDefault] = React.useState([]); React.useEffect(() => { getListing('real_estates') }, []) const getListing = async (url) => { const config = { method: 'GET' }; const response = await fetch(`${process.env.REACT_APP_API_URL}/${url}`, config); const data = await response.json(); setFlatsDefault(data) }; // 用useMemo缓存过滤结果,避免重复计算 const filteredFlats = React.useMemo(() => { if (!searchQuery) return flatsDefault; return flatsDefault.filter(flat => flat.title.toLowerCase().includes(searchQuery.toLowerCase()) ); }, [searchQuery, flatsDefault]); return ( <> {/* 移除原来的本地输入框 */} <div className="home-header"> <div className="bg-img-desc"> <h1>List of real estates</h1> </div> </div> <div className="container" style={{ padding: '0 3.5rem' }}> <ul className="row"> {filteredFlats.length > 0 ? ( filteredFlats.map(flat => ( <li className="col-12 col-sm-6 col-md-4 col-lg-3 mb-4" key={uuid_v4()}> <div className="card h-100"> { flat.images_url && <img src={`${process.env.REACT_APP_API_URL}${flat.images_url[0]}`} className="card-img-top" alt=""/> } <div className="card-body"> <h5>{flat.title}</h5> <p>Price : {flat.price} €</p> <p>location : {flat.location}</p> {connected && <Link to={`/real_estates/${flat.id}`} className="btn btn-primary">Details</Link>} </div> </div> </li> )) ) : ( <h2>No properties found matching your search</h2> )} </ul> </div> </>) }
4. 更新App.js,清理无用props
修改App.js里的NavbarComp调用,去掉不需要的props:
import React from 'react'; import { BrowserRouter as Router, Switch, Route } from "react-router-dom"; import { Layout } from 'antd'; import { NavbarComp } from "components/NavbarComp"; import { Home } from "pages/Home"; import Realestate from "pages/Realestate"; import NewRealestate from "pages/NewRealestate"; import { Other } from "pages/Other"; import { Login } from "pages/Login"; import { Register } from "pages/Register"; import Profile from "pages/Profile"; import { useDispatch, useSelector } from 'react-redux'; import { getUser } from 'redux/auth/authActions'; import Cookies from 'js-cookie'; function App() { const dispatch = useDispatch(); const user = useSelector(state => state.auth.user); React.useEffect(() => { dispatch(getUser(Cookies.get('id'))) }, [dispatch]) // 修复依赖警告 return ( <Layout className="layout" style={{ backgroundColor: 'transparent' }}> <Router> <NavbarComp /> {/* 不再需要传递input/setInput props */} <Switch> {/* 你的路由配置保持不变 */} <Route exact path="/"> <Home /> </Route> <Route exact path="/real_estates/:id"> <Realestate /> </Route> <Route path="/new_real_estate"> <NewRealestate /> </Route> <Route path="/other"> <Other /> </Route> <Route exact path="/login" > <Login /> </Route> <Route exact path="/register" > <Register /> </Route> <Route exact path="/profile" > <Profile user={user} /> </Route> </Switch> </Router> </Layout> ); } export default App;
为什么选Redux?
因为你的项目已经集成了Redux,不需要额外引入Context API或其他状态库,保持技术栈一致性的同时,还能轻松扩展——未来如果有其他组件需要用到搜索状态,直接用useSelector获取即可。
另外用useMemo缓存过滤结果,避免每次渲染都重复执行过滤逻辑,能小幅度提升页面性能。
内容的提问来源于stack exchange,提问作者pedrofromperu
相关产品推荐
相关产品推荐

