React Router疑问:已设exact,为何/a/b/d仍匹配/a/b路由?
exact还是匹配错路由?我来给你捋清楚 你遇到的这个问题,核心原因其实是react-router的<Switch>组件“认生”——它只会处理自己直接子节点里的<Route>或者<Redirect>组件。当你用自定义的WrapperRoute把<Route>包起来之后,Switch根本看不到里面的<Route>,它只会把WrapperRoute当成普通组件,一股脑把所有WrapperRoute都渲染出来,而不是按路径匹配只渲染第一个符合条件的。
咱们来看你的代码:你在WrapperRoute里给<Route>加了exact,但Switch不管这个,它先把两个WrapperRoute都渲染了,然后每个WrapperRoute里的<Route>自己去匹配路径。如果之前你没加exact,那第一个<Route path="/a/b">会匹配/a/b/d(因为前缀匹配),所以会显示Component A;现在你加了exact,理论上第一个<Route>不应该匹配/a/b/d,但你说还是匹配到了,大概率是你最开始的代码里exact没加对地方——比如你在WrapperRoute的props里传了exact,但没把它传递给内部的<Route>。
办法一:让WrapperRoute做个“传声筒”,把路由属性都传给内部的<Route>
修改WrapperRoute,让它接收所有路由相关的属性(比如exact、path这些),然后原封不动传给内部的<Route>。这样Switch虽然看到的是WrapperRoute,但内部的<Route>能正确拿到匹配规则,而且Switch的匹配逻辑也能间接生效:
function WrapperRoute(props) { // 把所有接收到的props都传给内部的Route const Page = props.component; return ( <Route {...props} render={() => <Page />} /> ); }
然后在App里用的时候,把exact也传给WrapperRoute(当然你也可以在WrapperRoute里默认加exact,但外部传的话更灵活):
{routes.map(route => { return ( <WrapperRoute key={route.path} exact path={route.path} component={route.component} /> ); })}
办法二:让<Route>直接当Switch的孩子,WrapperRoute只做内容包装
如果你的WrapperRoute只是用来包装路由内容,不是用来处理路由逻辑的,那可以把<Route>直接放在Switch里,把WrapperRoute作为<Route>的内容:
const App = () => ( <Router> <div> <Link to="/a/b">/a/b</Link> <br /> <Link to="/a/b/d">/a/b/d</Link> <Switch> {routes.map(route => { return ( <Route key={route.path} exact path={route.path}> <WrapperRoute> {route.component()} </WrapperRoute> </Route> ); })} </Switch> </div> </Router> ); // 现在WrapperRoute只负责包装内容 function WrapperRoute({ children }) { // 这里可以加你的包装逻辑,比如样式、权限校验之类的 return <div>{children}</div>; }
这样Switch能直接看到每个<Route>,按顺序匹配路径,完全符合你的预期。
Switch的本职工作就是找第一个路径匹配的直接子节点<Route>/<Redirect>,你用自定义组件把<Route>包起来,就等于把Switch的“眼睛”蒙住了,它就不会按规则过滤了。要么让自定义组件把路由属性都传下去,要么让<Route>直接当Switch的孩子,问题就解决啦~
内容的提问来源于stack exchange,提问作者Howard

