React Router V6中如何正确设置父级NavLink激活状态
场景与路由配置
我搭建了一个多层级导航,结构如下:
Home Companies Company Details Users
对应的React Router路由配置:
<Routes> <Route index element={<Home />} /> <Route path="companies" element={<Companies />}> <Route index element={<CompaniesList />} /> <Route path=":companyId" element={<Company />}> <Route index element={<CompanyDetail />} /> <Route path="users" element={<Users />}> <Route index element={<UserList />} /> <Route path=":userId" element={<UserDetail />} /> </Route> </Route> </Route> </Routes>
实际路由层级:
Companies: /companies - Details: /companies/:companyId - Users: /companies/:companyId/users - User Details: /companies/:companyId/users/:userId
当前问题
我用<NavLink>给导航项设置激活类:
<NavLink to="..." className={({ isActive }) => (isActive ? 'is-active' : '')} />
- 进入Details页面时,Details和Companies导航项正常激活;
- 进入Users页面(
/companies/:companyId/users)时,Companies、Details、Users三个都被激活,不希望Details激活; - 给Details的
<NavLink>加end属性后,Details不再错误激活,但Companies导航项也失去激活状态;进入User Details页面时,所有导航项都不激活; - 尝试用
useLocation()判断路径包含关系,因为/companies/:companyId/users包含/companies/:companyId,还是会错误匹配到Details。
需求
需要准确判断路由的真正父级关系:Companies是Users的父级,但Details不是。
解决方案
方法1:用useMatch精确匹配路由路径
React Router的useMatch钩子可以精确匹配路由规则,不会因为路径包含就误判。
- 对于Details导航项,只在路径完全匹配
/companies/:companyId时激活:
import { useMatch } from 'react-router-dom'; // 在导航组件中 const isDetailActive = useMatch('/companies/:companyId'); <NavLink to={`/companies/${companyId}`} className={isDetailActive ? 'is-active' : ''} > Company Details </NavLink>
- 对于Companies导航项,匹配所有
/companies开头的路由(包括子路由):
const isCompaniesActive = useMatch('/companies/*') || useMatch('/companies'); <NavLink to="/companies" className={isCompaniesActive ? 'is-active' : ''} > Companies </NavLink>
方法2:自定义正则匹配逻辑
用正则表达式精确匹配Details的路径,确保只有当路径是/companies/xxx(没有后续子路径)时才激活:
import { useLocation } from 'react-router-dom'; const location = useLocation(); // 匹配 /companies/任意字符,但后面不能有斜杠(即没有子路径) const detailPathRegex = /^\/companies\/[^\/]+$/; const isDetailActive = detailPathRegex.test(location.pathname); <NavLink to={`/companies/${companyId}`} className={isDetailActive ? 'is-active' : ''} > Company Details </NavLink>
方法3:基于路径层级判断
拆分当前路径的层级,Details的路径层级是2(companies/xxx),Users及子路由的层级是3+,以此区分:
import { useLocation } from 'react-router-dom'; const location = useLocation(); // 拆分路径并过滤空字符串,得到路径段数组 const pathSegments = location.pathname.split('/').filter(Boolean); // 只有路径段长度为2,且第一段是companies时,才激活Details const isDetailActive = pathSegments.length === 2 && pathSegments[0] === 'companies';
以上方法都能解决你的问题,推荐优先使用useMatch,它是React Router提供的原生方案,更贴合路由逻辑。
内容的提问来源于stack exchange,提问作者Phil
相关产品推荐
相关产品推荐

