React Router路由权限控制问题:多Route被同时渲染
我明白你遇到的问题了——当你用Auth组件包裹一组Route并放在Switch里时,访问匹配的路径会同时渲染多个组件,这其实是因为Switch的匹配规则只作用于它的直接子元素,而你的Route是嵌套在Auth组件内部的,Switch无法识别这些嵌套的Route,所以会把所有符合路径条件的Route都渲染出来。
下面给你几个可行的解决方案,你可以根据自己的代码风格选择:
方案1:在Auth组件内部添加Switch
最简单的修改方式就是在Auth组件校验通过后,用Switch把所有子Route包裹起来,这样内部的Route就会按照Switch的规则只匹配第一个符合条件的路径:
const AuthWrapper = ({ children, roles, ...props }) => { if (Authenticator(roles)) { // 用Switch包裹子元素,确保内部路由只渲染第一个匹配项 return <Switch>{children}</Switch>; } // 这里建议替换成跳转到登录页或者无权限页面,比返回null更友好 return <Redirect to="/login" />; };
你的原有路由结构不需要任何改动,这样修改后,访问/repos/时只会渲染Repos组件,访问/repos/somerepo时只会渲染Repo组件。
方案2:把Auth改造成路由高阶组件(HOC)
如果想让路由结构更清晰,推荐把Auth做成一个包裹组件的高阶组件,这样每个Route都直接作为Switch的子元素,完全符合Switch的工作逻辑:
先实现这个高阶组件:
const withAuth = (Component, allowedRoles) => { return (props) => { // 校验用户角色 if (Authenticator(allowedRoles)) { return <Component {...props} />; } // 权限不足时跳转 return <Redirect to="/login" />; }; };
然后在路由中使用:
<Switch> <Route exact path="/repos/" component={withAuth(Repos, ['user'])} /> <Route exact path="/repos/:repo" component={withAuth(Repo, ['user'])} /> <Route exact path="/repos/:repo/settings" component={withAuth(RepoSettings, ['admin'])} /> </Switch>
这种方式的优势是路由结构一目了然,每个Route的权限要求清晰可见,也避免了嵌套组件带来的Switch匹配问题。
方案3:直接在Route的render属性中做校验
如果你的权限逻辑不算复杂,也可以直接在Route的render属性里完成校验,省去额外的组件封装:
<Switch> <Route exact path="/repos/" render={(props) => Authenticator(['user']) ? <Repos {...props} /> : <Redirect to="/login" /> } /> <Route exact path="/repos/:repo" render={(props) => Authenticator(['user']) ? <Repo {...props} /> : <Redirect to="/login" /> } /> <Route exact path="/repos/:repo/settings" render={(props) => Authenticator(['admin']) ? <RepoSettings {...props} /> : <Redirect to="/login" /> } /> </Switch>
这种方式代码更直观,适合小型项目或者简单的权限场景。
总的来说,核心问题就是Switch无法处理嵌套在其他组件内的Route,只要让Route处于Switch的直接层级,或者在Auth内部用Switch来管理嵌套路由,就能解决多组件同时渲染的问题。
内容的提问来源于stack exchange,提问作者Milindu Sanoj Kumarage

