router icon indicating copy to clipboard operation
router copied to clipboard

Navigating to splat/catch-all routes always return the data of the first match

Open GuillaumeLaroucheUQAT opened this issue 1 year ago • 2 comments

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

  1. Click on "Splat Route" to navigate to the splat route.
  2. Click on "/page" to navigate to the subroute.
  3. 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.

GuillaumeLaroucheUQAT avatar Jan 23 '24 20:01 GuillaumeLaroucheUQAT

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.

GuillaumeLaroucheUQAT avatar Jan 30 '24 15:01 GuillaumeLaroucheUQAT

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.

GuillaumeLaroucheUQAT avatar Jan 30 '24 16:01 GuillaumeLaroucheUQAT