Navigating to splat/catch-all routes always return the data of the first match
Describe the bug
The first time a splat/catch-all route is matched, the data is cached and the page is rendered correctly, but subsequent matches after that always return the first match.
Your Example Website or App
https://stackblitz.com/edit/tanstack-router-rlxprr?file=src%2Froutes%2F%24.tsx
Steps to Reproduce the Bug or Issue
- Click on "Splat Route" to navigate to the splat route.
- Click on "/page" to navigate to the subroute.
- Nothing happen unless the page is refreshed.
Expected behavior
Clicking on "/page" should render the new match
Screenshots or Videos
No response
Platform
- OS: [Windows]
- Browser: [Chrome]
- Version: [120]
Additional context
From what I can see in the Devtools, Splat/catch-all routes uses the route's path as the key for the cache while dynamic routes uses the captured section of the URL pathname.
For exemple, a dynamic route services/$serviceId with the param service-a will use the pathname /services/service-a as the key but the splat route /services/$ will always use /services/$.
Maybe it could mean that the data returned from the cache is always the instance of the first match for a splat route.
The bug is located in the interpolatePath function of the path.ts file.
The following condition try to build the matchId for a wildcard segment :
if (segment.type === "wildcard") {
const value = params[segment.value];
if (leaveWildcards)
return `${segment.value}${value ?? ""}`;
return value;
}
The param retrieved for the segment value is undefined because the captured pathname in the params has the key _splat (* is also valid in v1) while the segment has the value $. Since the value is undefined, an empty string is appended to the segment so every paths in a splat route have the same matchId.
A temporary fix could be to use * instead of $ since both characters are checked to determine if a path is a splat route but the doc specify that * will be removed in v2 and a file cannot have the name *.tsx in file-based routing.