React Router中无需高阶函数实现组件间数据共享及路由渲染问题
解决方法
有两种常用方案可以满足你的需求:
方案1:将上下文提供者抽离为独立组件(推荐)
把上下文的状态管理和UI组件拆分开,让Provider独立包裹所有需要访问上下文的路由,这样不管是/flights还是/flights/flight-results都能拿到上下文数据,且各自只渲染对应组件。
步骤:
- 创建独立的上下文提供者组件
// FlightSearchProvider.tsx import { createContext, useContext, useState } from 'react'; // 定义上下文 const FlightSearchContext = createContext(null); export const FlightSearchProvider = ({ children }) => { // 在这里定义原来Flights组件里的所有状态(比如typeOfTrip、fromAirport等) const [typeOfTrip, setTypeOfTrip] = useState('one-way'); const [fromAirport, setFromAirport] = useState(''); const [departureDate, setDepartureDate] = useState(''); const [returnDate, setReturnDate] = useState(''); const [toAirport, setToAirport] = useState(''); const [outGoingFlights, setOutGoingFlights] = useState([]); const [searchAirports, setSearchAirports] = useState([]); return ( <FlightSearchContext.Provider value={{ typeOfTrip, fromAirport, departureDate, returnDate, toAirport, outGoingFlights, searchAirports, setSearchAirports, // 记得把所有需要传递的setter也加上 }} > {children} </FlightSearchContext.Provider> ); }; // 封装自定义hook,方便其他组件调用 export const useFlightSearch = () => useContext(FlightSearchContext);
- 修改原Flights组件,只保留自身UI
// Flights.tsx const Flights = () => { // 如果需要用到上下文数据,用自定义hook获取即可 // const { ... } = useFlightSearch(); return <h1>Some UI</h1>; }; export default Flights;
- 配置路由,让两个路由都在Provider范围内
// index.tsx路由配置 import { Routes, Route } from 'react-router-dom'; import { FlightSearchProvider } from './FlightSearchProvider'; import Flights from './Flights'; import FlightResults from './FlightResults'; function App() { return ( <FlightSearchProvider> <Routes> <Route path="/flights" element={<Flights />} /> <Route path="/flights/flight-results" element={<FlightResults />} /> </Routes> </FlightSearchProvider> ); } export default App;
这种方案把上下文管理和UI彻底解耦,后续新增需要上下文的页面也很方便,代码结构更清晰。
方案2:在Flights组件中根据路由判断是否显示自身UI
如果不想新增组件,可以通过路由路径判断,只在访问/flights时显示Flights的UI,访问子路由时仅渲染<Outlet/>。
修改Flights组件:
import { Outlet, useLocation } from 'react-router-dom'; const Flights = () => { const location = useLocation(); // 只有当路径是/flights时才显示自身UI const shouldShowFlightsUI = location.pathname === '/flights'; return ( <FlightSearchContext.Provider value={{ typeOfTrip, fromAirport, departureDate, returnDate, toAirport, outGoingFlights, searchAirports, setSearchAirports, }} > {shouldShowFlightsUI && <h1>Some UI</h1>} <Outlet /> </FlightSearchContext.Provider> ); }; export default Flights;
路由配置保持嵌套:
<Routes> <Route path="/flights" element={<Flights />}> <Route path="flight-results" element={<FlightResults />} /> </Route> </Routes>
这种方案不需要额外拆分组件,但把路由逻辑耦合在了Flights组件里,适合快速临时解决问题。
内容的提问来源于stack exchange,提问作者Amos Machora
相关产品推荐
相关产品推荐

