react-router中withRouter有何替代方案?子组件如何获取match属性
React Router v6 中withRouter的替代方案
React Router 从v6版本开始正式移除了withRouter高阶组件,无需降级版本、无需逐层透传props,使用官方提供的路由Hooks即可实现完全一致的能力。
核心API对应关系
原有withRouter会向组件注入match/location/history三个路由相关属性,v6中对应Hook如下:
- 路由跳转能力(原
history.push/history.replace):使用useNavigate()Hook - 当前路径信息、匹配参数(原
match.url/match.params):使用useResolvedPath()、useMatch()、useParams()Hook - 当前路由位置对象(原
location):使用useLocation()Hook
注意:禁止直接操作
window.history实现跳转,React Router内部维护了独立的路由上下文状态,直接修改原生history对象会导致路由状态不同步、嵌套路由匹配失效、导航守卫不触发等异常,所有跳转逻辑请使用官方提供的导航API。
原组件改造示例(函数组件)
针对提供的MenuItem组件,改造后代码如下,完全保留原有交互逻辑:
import React from "react"; import './menuItem.style.scss' import { useNavigate, useResolvedPath } from "react-router"; const MenuItem = ({title, imageUrl,size,linkUrl}) => { const navigate = useNavigate(); // 解析当前路由下拼接linkUrl的目标路径,替代原match.url拼接逻辑 const targetPath = useResolvedPath(linkUrl); return ( <div className={`${size} menu-item`} onClick={() => navigate(targetPath.pathname)} > <div style={{backgroundImage: `url(${imageUrl})`}} className="background-image" ></div> <div className="content"> <h1 className="title">{title.toUpperCase()}</h1> <span className="subtitle">Shop Now</span> </div> </div> ) }; export default MenuItem;
类组件兼容方案
如果你使用的是类组件无法直接使用Hook,可以自行封装和旧版API完全一致的withRouter高阶组件,无需修改原有业务代码:
import { useNavigate, useLocation, useParams } from 'react-router'; export const withRouter = (WrappedComponent) => { function WithRouterWrapper(props) { const navigate = useNavigate(); const location = useLocation(); const params = useParams(); // 组装和旧版withRouter一致的props结构 const routerProps = { match: { url: location.pathname, params: params }, location, history: { push: navigate, replace: (path) => navigate(path, {replace: true}) } }; return <WrappedComponent {...routerProps} {...props} />; } return WithRouterWrapper; };
封装完成后,原有组件的export default withRouter(MenuItem)写法可以直接保留,不需要做其他修改。
内容的提问来源于stack exchange,提问作者Almas
相关产品推荐
相关产品推荐

