T
TanStack4mo ago
rare-sapphire

Dynamic search params without reloadDocument

I try to achieve dyanamic filters component based on searchParams. On my page i want to display products which need to be filtered by selected filters. It works like expected but due to change search params, the whole route reload. Once we have these deps in place, the route will always reload when the deps change. On my filters component I use share params to select/deselect filters checkboxes. If request take a while, the checkbox select with delay because search params update after loader finish. There is any way to update searchParams and not triger route reload?
void navigate({
to: '.',
search: {
"color": "red",
},
reloadDocument: false,
});
void navigate({
to: '.',
search: {
"color": "red",
},
reloadDocument: false,
});
export const Route = createFileRoute('/_pathlessLayout/$')({
component: RouteComponent,
loaderDeps: (search) => search,
loader: async ({ params, deps }) => {
const { products, filters } = await fetchSearchProducts({
data: {
filters: deps.search,
},
});
return {
products,
filters,
};
},
});
export const Route = createFileRoute('/_pathlessLayout/$')({
component: RouteComponent,
loaderDeps: (search) => search,
loader: async ({ params, deps }) => {
const { products, filters } = await fetchSearchProducts({
data: {
filters: deps.search,
},
});
return {
products,
filters,
};
},
});
9 Replies
national-gold
national-gold4mo ago
if you dont want a search param to trigger the loader, then dont include it in loaderDeps
rare-sapphire
rare-sapphireOP4mo ago
Ok but i need searchParams in loader to fetch data, there is any other way to get search params in loaders instead deps?
national-gold
national-gold4mo ago
no so what is really the issue here? don't you want the loader to run when you change the search params?
rare-sapphire
rare-sapphireOP4mo ago
yep i want to make filters more dynamic. - on the first load search params should be taken to loader and fetch initial product - after user select filter it should immeditly go to url ( i want to have url state for filters) - useSearch hook should return new search params - new search params used in useQuery to get new products so i want to combine initial data from loader with useQuery hook
national-gold
national-gold4mo ago
can you provide a complete minimal example that shows the issue of the delay?
rare-sapphire
rare-sapphireOP4mo ago
Firstly i would like to not refetch data if searchParams change. For now keep that i not use searchParams in Loader
import { createFileRoute, notFound } from '@tanstack/react-router';

import { Filters } from '~/components/Filters';
import { fetchCategory } from '~/server/categories.server';
import { fetchSearchProducts } from '~/server/products.server.ts';

export const Route = createFileRoute('/_pathlessLayout/$category-slug')({
component: RouteComponent,
// loaderDeps: (search) => search,
loader: async ({ params }) => {
const category = await fetchCategory({
data: params['category-slug'] ?? '/',
});
if (!category) {
throw notFound();
}
const { products, filters } = await fetchSearchProducts({
data: {
categoryId: category.id,
filters: {},
},
});
return {
category,
products,
filters,
};
},
});

function RouteComponent() {
const { category, products, filters } = Route.useLoaderData();

const searchParams = Route.useSearch();
return (
<div>
<div>{category.name}</div>
<div>{products.length}</div>
<div className="grid grid-cols-2">
<Filters filters={filters} searchParams={searchParams} />
<div>
{products.map((product) => (
<div key={product.id}>
<div>{product.title}</div>
<div>{product.id}</div>
</div>
))}
</div>
</div>
</div>
);
}
import { createFileRoute, notFound } from '@tanstack/react-router';

import { Filters } from '~/components/Filters';
import { fetchCategory } from '~/server/categories.server';
import { fetchSearchProducts } from '~/server/products.server.ts';

export const Route = createFileRoute('/_pathlessLayout/$category-slug')({
component: RouteComponent,
// loaderDeps: (search) => search,
loader: async ({ params }) => {
const category = await fetchCategory({
data: params['category-slug'] ?? '/',
});
if (!category) {
throw notFound();
}
const { products, filters } = await fetchSearchProducts({
data: {
categoryId: category.id,
filters: {},
},
});
return {
category,
products,
filters,
};
},
});

function RouteComponent() {
const { category, products, filters } = Route.useLoaderData();

const searchParams = Route.useSearch();
return (
<div>
<div>{category.name}</div>
<div>{products.length}</div>
<div className="grid grid-cols-2">
<Filters filters={filters} searchParams={searchParams} />
<div>
{products.map((product) => (
<div key={product.id}>
<div>{product.title}</div>
<div>{product.id}</div>
</div>
))}
</div>
</div>
</div>
);
}
And then in Filters component fire:
void navigate({
to: '.',
ignoreBlocker: true,
search: {
[filter.handle]: next.length > 0 ? next : undefined,
},
reloadDocument: false,
});
void navigate({
to: '.',
ignoreBlocker: true,
search: {
[filter.handle]: next.length > 0 ? next : undefined,
},
reloadDocument: false,
});
After run that navigate whole route reload
national-gold
national-gold4mo ago
reloadDocument: false, should not be necessary since that's the default aside from that, if you can provide a ready to run example repository i might have a look
eastern-cyan
eastern-cyan4mo ago
Not sure if its the same issue, but i have a serverFN call in my root route beforeLoad, and changing searchparams via navigate (without a loader dep) triggers this beforeLoad repeatedly
export const Route = createRootRouteWithContext<RouterAppContext>()({
beforeLoad: async () => {
const { authSession } = await fetchAuthSession();
return {
authSession,
};
},
export const Route = createRootRouteWithContext<RouterAppContext>()({
beforeLoad: async () => {
const { authSession } = await fetchAuthSession();
return {
authSession,
};
},
Not sure if that is intended or not
national-gold
national-gold4mo ago
beforeLoad runs upon every navigation we are working on adding another lifecycle method with the same cache semantics as loader that will be more appropriate for auth checks like this

Did you find this page helpful?