T
TanStack•11mo ago
rival-black

useSearch on a dynamic hook

Hi everyone I'm trying to build a dynamic hook to handle the things for the tanstack table, like: - pagination - filters - etc How I can use the useSearch dynamically without have everything as any 😦 Anyone already did something similar?
18 Replies
equal-aqua
equal-aqua•10mo ago
you can use strict: false
rival-black
rival-blackOP•10mo ago
I'm following an example where the guy use the navigate to set the search, but I have the same issue
No description
rival-black
rival-blackOP•10mo ago
No description
rival-black
rival-blackOP•10mo ago
The entire code:
function cleanEmptyParams<T extends Record<string, unknown>>(search: T) {
const newSearch: T = { ...search };

Object.keys(newSearch).forEach((key) => {
const value = newSearch[key];

if (value === undefined || value === '' || (typeof value === 'number' && Number.isNaN(value))) {
delete newSearch[key];
}
});

return newSearch;
}

function useFilters<TId extends RouteIds<RegisteredRouter['routeTree']>>(routeId: TId) {
const routeApi = getRouteApi<TId>(routeId);
const navigate = useNavigate();
const filters = routeApi.useSearch();

function setFilters(partialFilters: Partial<typeof filters>) {
return navigate({
search: (prev) => cleanEmptyParams({ ...prev, ...partialFilters }),
});
}

function resetFilters() {
navigate({ search: undefined });
}

return { filters, setFilters, resetFilters };
}
function cleanEmptyParams<T extends Record<string, unknown>>(search: T) {
const newSearch: T = { ...search };

Object.keys(newSearch).forEach((key) => {
const value = newSearch[key];

if (value === undefined || value === '' || (typeof value === 'number' && Number.isNaN(value))) {
delete newSearch[key];
}
});

return newSearch;
}

function useFilters<TId extends RouteIds<RegisteredRouter['routeTree']>>(routeId: TId) {
const routeApi = getRouteApi<TId>(routeId);
const navigate = useNavigate();
const filters = routeApi.useSearch();

function setFilters(partialFilters: Partial<typeof filters>) {
return navigate({
search: (prev) => cleanEmptyParams({ ...prev, ...partialFilters }),
});
}

function resetFilters() {
navigate({ search: undefined });
}

return { filters, setFilters, resetFilters };
}
equal-aqua
equal-aqua•10mo ago
which example are you following ? I still think strict: false is the solution
rival-black
rival-blackOP•10mo ago
GitHub
tanstack-filtered-table-demo/src/hooks/useFilters.ts at main · Bala...
Managing table pagination, filtering and sorting on query parameters with the TanStack - Balastrong/tanstack-filtered-table-demo
rival-black
rival-blackOP•10mo ago
Because my idea is the filters be on the FE URL and use the same query parameters to send on the BE request Any idea? Or a better example?
equal-aqua
equal-aqua•10mo ago
did you try this?
rival-black
rival-blackOP•10mo ago
The navigate function doesn't have any. strict option
equal-aqua
equal-aqua•10mo ago
right! I was looking at useSearch but you could try passing to: "." into navigate
rival-black
rival-blackOP•10mo ago
Seems to working On quick question, how do you usually do to put strings, arrays, etc into the query parameters
inland-turquoise
inland-turquoise•10mo 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
rival-black
rival-blackOP•10mo ago
Already take a look, but how you handle spaces, arrays, for example
inland-turquoise
inland-turquoise•10mo ago
TanStack router handles that for you. The first code snippet on the page shows numbers, arrays, strings, and booleans being used
No description
inland-turquoise
inland-turquoise•10mo ago
in your actual route, it would look something like this if you're using zod for validation
No description
inland-turquoise
inland-turquoise•10mo ago
and then you can acces those search params in your components like so
No description
rival-black
rival-blackOP•10mo ago
I'm already using zod
const customersSearchSchema = z.object({
page: z.number().catch(DEFAULT_PAGE),
limit: z.number().catch(DEFAULT_PAGE_SIZE),
sortBy: z.string().optional(),
orderBy: z.union([z.literal('desc'), z.literal('asc')]).optional(),
search: z.string().optional(),
});

const Route = createFileRoute('/_admin/customers/')({
validateSearch: customersSearchSchema,
component: CustomersList,
});
const customersSearchSchema = z.object({
page: z.number().catch(DEFAULT_PAGE),
limit: z.number().catch(DEFAULT_PAGE_SIZE),
sortBy: z.string().optional(),
orderBy: z.union([z.literal('desc'), z.literal('asc')]).optional(),
search: z.string().optional(),
});

const Route = createFileRoute('/_admin/customers/')({
validateSearch: customersSearchSchema,
component: CustomersList,
});
inland-turquoise
inland-turquoise•10mo ago
So then you would just use Zod's z.array() for arrays

Did you find this page helpful?