router
router copied to clipboard
Nested route match the first path with component
Describe the bug
I have a router like this
export const router = createReactRouter({
routeConfig: createRouteConfig().createChildren(createRoute => [
createRoute({
path: '/',
component: Home,
}),
createRoute({
path: 'collections',
// component: Collections,
}).createChildren(createRoute => [
createRoute({
path: ':collectionId',
component: Collection,
}).createChildren(createRoute => [
createRoute({
path: 'images'
}).createChildren(createRoute => [
createRoute({
path: ':imageId',
component: Image,
})
])
])
]),
])
});
And it only renders the first component in the path. If I go to /collections/new-collection/images/new-image
it renders the Collection component, if I uncomment Collections component it renders Collections component.
Thank you for any help 🙏🏻
Your Example Website or App
https://stackblitz.com/edit/vitejs-vite-rs1z4u?file=src/App.tsx
Steps to Reproduce the Bug or Issue
...
Expected behavior
Match the longest matching path.
Screenshots or Videos
No response
Platform
- OS: macOS
- Browser: Brave
- Version: 1.45.131 (Chromium: 107.0.5304.110)
Additional context
No response
Try change path: 'collections', // component: Collections,
path: 'collections', // component: Outlet,
It then passes through collections as if it's commented out, but otherwise exhibit the same behavior that router matches the "shortest" matching path, not the longest, which IMHO it should...
You need in add <Outlet />
in the components Collections
and Collection
. That is where the nested routes will render.
Here is a modified stackblitz that works: https://stackblitz.com/edit/vitejs-vite-bkplun?file=src/App.tsx
Thank you @wizzymore and @XpamAmAdEuS. I've got it :). So there is no way how to render just the longest matching route (like exact match in React Router) then to acculumate all the stuff along the way?
You can create just one route and put it above the nested ones, that should work.
EDIT: To be more specific, create one route with the path: '/collections/new-collection/images/new-image' if you want to have only one "catch"
Unfortunatelly I don't want only one "catch-all" route. I want one route for viewing all image collections (/collections), another one for viewing all images in particular collection (/collections/:collectionId or /collections/:collectionId/images) and another one for viewing just one image from particular collection (/collections/:collectionId/images/:imageId).
I was able to achieve that by using:
export const router = createReactRouter({
routeConfig: createRouteConfig().createChildren(createRoute => [
createRoute({
path: '/',
component: Home
}),
createRoute({
path: 'collections/:collectionId/images/:imageId',
component: Image
}),
createRoute({
path: 'collections/:collectionId',
component: Collection
}),
createRoute({
path: 'collections',
component: Collections
}),
])
});
I still think this a bug, since this should probably have the same semantics as the one using the child nodes...
Anyway, thank you @wizzymore for pointing me in the right direction to circumvent the issue 🙏🏻
To tie up loose ends here, I believe this is what you are looking for:
const rootRoute = createRouteConfig({})
const indexRoute = rootRoute.createRoute({
path: '/',
component: Home,
})
const collectionsRoute = rootRoute.createRoute({
path: 'collections',
component: Collections,
})
const collectionIndexRoute = collectionsRoutes.createRoute({
path: '/',
component: CollectionIndex,
})
const collectionRoute = collectionsRoutes.createRoute({
path: ':collectionId',
component: Collection,
})
const imagesRoute = collectionRoute.createRoute({
path: 'images',
component: Image,
})
const imageRoute = collectionRoute.createRoute({
path: ':imageId',
component: Image,
})
const routes = createReactRouter({
routes: rootRoute.addChildren([
indexRoute,
collectionsRoute.addChildren([
collectionIndexRoute,
collectionRoute.addChildren([imagesRoute.addChilren([imageRoute])]),
]),
]),
})