Repository navigation
useRoute in nested Router with basepath cannot match absolute path #244
Description
Activity
@waful i have a doubt, why not distinguish by path, you need to use base? Maybe I didn't understand
@cbbfcd
Elaborated contrived example:<TopLevelRouter> <ChildRouter base='/userTypeA'> ... <Route path='/settings' component={SharedSettingsComponent} /> <Route path='/otherSharedPage' component={SharedPageComponent} /> <Route path='/featureA' component={FeatureAComponent} /> <Route path='/' component={TypeAComponent} /> ... </ChildRouter> <ChildRouter base='/userTypeB'> ... <Route path='/settings' component={SharedSettingsComponent} /> <Route path='/otherSharedPage' component={SharedPageComponent} /> <Route path='/' component={TypeBComponent} /> ... </ChildRouter> </TopLevelRouter>I have 2 user types with some shared pages and some type specific pages nested in their respective routers. The settings page for both users are for the most part identical with minor styling/wording changes, so I want to use the same component with a switch flag instead of creating two completely distinct components. I want to be able to identify the nested base route I'm currently in from within
SharedSettingsComponent, but theuseRouteinside it can only match/settingsand not/userType(A|B)/settings. No matter if you're in/userTypeA/settingsor/userTypeB/settingsyou can only match the same path/settings.<Link>handles this today already, you can<Link href='/otherSharedPage'>from insideSharedSettingsComponentand it will go to/userType(A|B)/otherSharedPagebased on whichChildRouteryou're in, and you can link outside of the current nested base path for example with<Link href='~/userTypeA/otherSharedPage'>even if you're in/userTypeB. ButuseRoutedoes not have a similar capability to interact outside of its current nested router context via the~prefix.EDIT: upon revisiting this problem I wonder if I could just use
useRouterand grabrouter.basefor this specific scenario. However this is just another workaround like usingwindow.location.hrefand the issue remains thatuseRoutehas no way to match absolute route. TheuseRouterworkaround would not work with multiple nested routers because it would only grab the immediate base path and not the full base bath.- addedV3Features that won't be released in v2, but planned for the next major releaseFeatures that won't be released in v2, but planned for the next major release
on Nov 22, 2023 i want made something similar, look exemple:
function Item({ label, href }) { const [match] = useRoute(href) return ( match ? <li className='selected'><Link href={href}>{label}</Link></li> : <li><Link href={href}>{label}</Link></li> ); }; function MainMenu() { return ( <ul> <Item label="A" href="section-A" /> <Item label="B" href="section-B" /> </ul> ) }; function SubMenu() { return ( <> <Item label="1" href="/option-1" /> <Item label="2" href="/option-2" /> </> ) }; function App() { return ( <Router> <MainMenu /> <Switch> <Route path="/section-A"> <NestedRouter base="/section-A"> <SubMenu /> <Switch> <Route path="/option-1"> <h1>Option 1 from Section A</h1> </Route> <Route path="/option-2"> <h1>Option 2 from Section A</h1> </Route> </Switch> </NestedRouter> </Route> <Route path="/section-B"> <NestedRouter base="/section-B"> <SubMenu /> <Switch> <Route path="/option-1"> <h1>Option 1 from Section B</h1> </Route> <Route path="/option-2"> <h1>Option 2 from Section B</h1> </Route> </Switch> </NestedRouter> </Route> </Switch> </Router> ) }; ReactDOM.createRoot(document.getElementById('root')).render( <React.StrictMode> <App /> </React.StrictMode> )The
NestedRouteris from example on docs.So what i want is that my
Itemcomponent can figure out if he is a selected item byuseRoute, on first level it works, but on the others doest.If i have selected a item on
MainMenu, he becomeselected, but if i select another item onSubMenu, the previous selected item become unselected. Thinking that current selected item fromSubMenuis inside a nested router, the item onMainMenuneed be selected too, butuseRoutedoesnt match./section-A-> onlyMainMenuitem is selected and its OK.
/section-A/option1-> item fromMainMenuis unselected and onlySubMenuitem is selected, but i think that is a wrong.I think that
useRoutecalled insideItemfromMainMenushould match with href/section-A/option-1, by the routing structure.I figure out how to work around, with:
const [match] = useRoute(href + "/:any*");So the
Itemcomponent became:function Item({ label, href }) { const [match] = useRoute(href + "/:any*"); return ( match ? <li className='selected'><Link href={href}>{label}</Link></li> : <li><Link href={href}>{label}</Link></li> ); };Now he matches with base path froim nested router and routes on sub menu.
- removedV3Features that won't be released in v2, but planned for the next major releaseFeatures that won't be released in v2, but planned for the next major release
on Mar 4, 2024 - added a commit that references this issue
on Sep 5, 2026 Fixed in #570.
useRoute("~/...")now matches the full path, including inside nested routers.
When you use
useRoutein a nestedRouterwithbasepathspecified, the path matching only matches the path portion after the base path. For example, in the following configuration,The
useRouteinsideComponentcannot match absolute paths like~/test/:rest*(the wayLinks can), meaning there is no way to figure out if the current path is under/testor/othertest. Looking at the matcher source code, this is just a functionality that has not been implemented. But from a conceptual, functional point of view, is this considered a bug? I would think that there should be a way to match full path without resorting towindow.location.href?