React Router:如何在Switch中合规使用高阶私有路由组件?
符合官方规范的两种解决方案
我来给你两个完全满足react-router官方要求的方案,帮你顺利通过代码评审:
方案一:用高阶组件(HOC)包裹鉴权逻辑,配合常规Route组件
这是最推荐的方案,完全遵循Switch只接受Route子组件的官方规则。核心思路是把鉴权逻辑封装成高阶组件,再用它包裹需要保护的页面组件,最后作为Route的component属性传入。
代码实现
首先定义鉴权高阶组件:
import { Redirect } from 'react-router-dom'; // 接收鉴权规则数组和目标组件,返回带鉴权逻辑的包装组件 const withAuth = (authCriteria, Component) => { return (props) => { // 校验所有鉴权规则 const isAuthorized = authCriteria.every(criteria => criteria(props)); if (isAuthorized) { // 鉴权通过,渲染目标组件并传递所有路由props return <Component {...props} />; } else { // 鉴权失败,重定向到首页(可根据需求修改跳转目标) return <Redirect to="/" />; } }; };
然后修改你的路由配置:
import { Router, Route, Switch } from 'react-router-dom'; const authCriteria = [ props => props.location.state?.from !== undefined, ]; const AppRouter = () => { return ( <Router> <Switch> <Route exact path='/' component={Store} /> {/* 用withAuth包裹需要鉴权的组件,作为Route的component */} <Route exact path='/account' component={withAuth(authCriteria, Account)} /> <Route exact path='/shipping' component={withAuth(authCriteria, Shipping)} /> <Route exact path='/checkout' component={withAuth(authCriteria, Checkout)} /> {/* 404兜底路由,完全符合Switch的官方要求 */} <Route render={() => (<h2>Not Found</h2>)} /> </Switch> </Router> ); }; export default AppRouter;
方案优势
- 所有Switch的子元素都是标准Route组件,完全符合官方文档规范,代码评审无压力
- 高阶组件的方式灵活性高,可针对不同路由传入不同的
authCriteria,也能轻松扩展鉴权失败的处理逻辑 - 保留了Switch的路由优先级匹配特性,适合复杂的路由结构
方案二:不使用Switch实现404兜底路由
如果不想依赖Switch,可以利用Route的匹配规则实现404。核心是给所有业务路由加上exact,最后放一个无path的Route作为兜底(会匹配所有路径)。
代码实现
import { Router, Route, Redirect } from 'react-router-dom'; const authCriteria = [ props => props.location.state?.from !== undefined, ]; // 封装鉴权路由逻辑,直接返回Route组件 const AuthRoute = ({ component: Component, authCriteria, ...rest }) => { return ( <Route {...rest} render={(props) => { const isAuthorized = authCriteria.every(criteria => criteria(props)); return isAuthorized ? <Component {...props} /> : <Redirect to="/" />; }} /> ); }; const AppRouter = () => { return ( <Router> {/* 所有业务路由都加exact确保精确匹配 */} <Route exact path='/' component={Store} /> <AuthRoute exact path='/account' component={Account} authCriteria={authCriteria} /> <AuthRoute exact path='/shipping' component={Shipping} authCriteria={authCriteria} /> <AuthRoute exact path='/checkout' component={Checkout} authCriteria={authCriteria} /> {/* 无path的Route会匹配所有路径,只有前面的路由都不匹配时才会渲染 */} <Route render={() => (<h2>Not Found</h2>)} /> </Router> ); }; export default AppRouter;
方案局限
- 仅适合所有业务路由都是精确匹配的场景,如果有非精确匹配的路由(比如
path='/products'),可能会和后面的路由同时渲染 - 缺少Switch的优先级匹配逻辑,路由顺序的影响会更明显
内容的提问来源于stack exchange,提问作者user8099936
相关产品推荐
相关产品推荐

