T
TanStack10mo ago
rare-sapphire

Link with search param having multiple values for same key

I'd like to provide a search property to my Link component where they query string key can have multiple values (an array)
<Link to="/foo/bar" search={{group_by: ['foo', 'bar']}} ...>
<Link to="/foo/bar" search={{group_by: ['foo', 'bar']}} ...>
This does work, but the query string in the browser is shown like this:
?group_by=%5B"foo"%2C"bar"%5D
?group_by=%5B"foo"%2C"bar"%5D
It does work technically. But I'd like it to be:
?group_by=foo&group_by=bar
?group_by=foo&group_by=bar
but I don't know how to make that happen. If I try to set the query string to the to property
<Link to="/foo/bar?group_by=foo&group_by=bar" ...>
<Link to="/foo/bar?group_by=foo&group_by=bar" ...>
I get a type error that the route is not any of those I've defined in my router config. My current route definition is as follows:
const GroupByEnum = z.enum([
'type', 'size', 'height'
]);

const routeValidator = z.object({
group_by: z.union([z.array(GroupByEnum), GroupByEnum]) // Accepts array or single value
});

export const Route = createFileRoute('/report')({
validateSearch: zodSearchValidator(routeValidator),
});
const GroupByEnum = z.enum([
'type', 'size', 'height'
]);

const routeValidator = z.object({
group_by: z.union([z.array(GroupByEnum), GroupByEnum]) // Accepts array or single value
});

export const Route = createFileRoute('/report')({
validateSearch: zodSearchValidator(routeValidator),
});
13 Replies
rival-black
rival-black10mo ago
TanStack | High Quality Open-Source Software for Web Developers
Headless, type-safe, powerful utilities for complex workflows like Data Management, Data Visualization, Charts, Tables, and UI Components.
From An unknown user
From An unknown user
rare-sapphire
rare-sapphireOP10mo ago
Thanks! I just quickly tried and it seems that part is deprecated..? I didn't have enough time to evaluate my IDE's suggestion about the
params: {parse, stringify}
params: {parse, stringify}
, but at least in the first minutes I couldn't get it work. I'll go deeper later. 👍
rival-black
rival-black10mo ago
what is deprecated?
rare-sapphire
rare-sapphireOP10mo ago
Sorry for being so vague. My IDE says these properties are not available for the router:
parseSearch: parseSearchWith(JSON.parse),
stringifySearch: stringifySearchWith(JSON.stringify),
parseSearch: parseSearchWith(JSON.parse),
stringifySearch: stringifySearchWith(JSON.stringify),
rare-sapphire
rare-sapphireOP10mo ago
I get this kind of an error message. I'm not sure how to continue from here 😅
No description
rival-black
rival-black10mo ago
can you please provide a complete minimal example? e.g. by forking one of the existing examples on stackblitz
rare-sapphire
rare-sapphireOP10mo ago
I think I managed to create a minimal example. If you open the "app" in a browser and click the "Click me", you'll see what I mean. https://stackblitz.com/edit/github-9yjfke?file=src%2Fposts.lazy.tsx
StackBlitz
Router Basic Example - StackBlitz
Run official live example code for Router Basic, created by Tanstack on StackBlitz
rival-black
rival-black10mo ago
you need to adapt the parseSearch in createRouter
rival-black
rival-black10mo ago
Manuel Schiller
StackBlitz
Router Basic Example (forked) - StackBlitz
Run official live example code for Router Basic, created by Tanstack on StackBlitz
rare-sapphire
rare-sapphireOP10mo ago
Not sure what you mean, this looks identical to my example. 😅 Even the stackblitz says the parseSearch isn't a valid property for the router. Nevertheless, I really appreciate you taking time trying to help me!
extended-salmon
extended-salmon10mo ago
@janne did you happen to figure this out? I'm currently working on the same thing 🙂
ambitious-aqua
ambitious-aqua10mo ago
Manuel is referring to these methods from the docs: https://tanstack.com/router/latest/docs/framework/react/guide/custom-search-param-serialization In your code you need to modify it:
const router = createRouter({
routeTree,
defaultPreload: 'intent',
defaultStaleTime: 5000,
parseSearch: parseSearchWith(JSON.parse), //Add a parse method like this
stringifySearch: stringifySearchWith(JSON.stringify), //Add a stringify method like this
});
const router = createRouter({
routeTree,
defaultPreload: 'intent',
defaultStaleTime: 5000,
parseSearch: parseSearchWith(JSON.parse), //Add a parse method like this
stringifySearch: stringifySearchWith(JSON.stringify), //Add a stringify method like this
});
In your example you are not defining the methods added above:
parseSearch
parseSearch
or
stringifySearch
stringifySearch
. In the docs I linked they show a few different libraries for this that have their own customization options, or you can write your own parse/stringify as well
Custom Search Param Serialization | TanStack Router React Docs
Diagram showing idempotent nature of URL search param serialization and deserializationBy default, TanStack Router parses and serializes your URL Search Params automatically using JSON.stringify and JSON.parse. This process involves escaping and unescaping the search string, which is a...
rare-sapphire
rare-sapphireOP9mo ago
@lmfao sorry I didn't. I just let it be as it is - the url's query string is only ugly, but it works. And my bad, I read the docs very poorly: the linked material points to createRouter, not createRoute. 🤦‍♂️ That's why my IDE was complaining. But again, I don't understand how I could use the parse/stringify to split my group_by to multiple items in query string as the stringifySearch receives only the list of values but doesn't know anything about the query string key it belongs to.

Did you find this page helpful?