Loading Page on router.push
Unanswered
Alaskan Malamute posted this in #help-forum
Alaskan MalamuteOP
Hey guys i am relativly new to next.js and was wanderinf if there is a way to set the page back to the loading state on pushing searchparams using router.push. My Code currently looks like this:
-- dashboard/citizens/page.tsx
export default async function CitizensPage({ searchParams }: { searchParams: Promise<{ query?: string; page?: number }> }) {
const citizens = await getCitizens({ searchParams: await searchParams });
return (
<>
<PageHeader>
<PageHeader.Title>Personen</PageHeader.Title>
<PageHeader.Buttons>
<SearchQueryInput placeholder={'Person suchen...'} />
</PageHeader.Buttons>
</PageHeader>
<Card className={'p-4'}>
<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Alias</TableHead>
<TableHead>Tags</TableHead>
<TableHead>Waffenschein gültig bis</TableHead>
<TableHead>Telefonnummer</TableHead>
<TableHead>Geschlecht</TableHead>
<TableHead>Geburtsdatum</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{citizens.map((citizen) => (
<TableRow key={citizen.id}>
</TableRow>
))}
</TableBody>
</Table>
</Card>
</>
);
}
-- SearchQueryInput.tsx
export function SearchQueryInput({ placeholder }: { placeholder?: string }) {
const router = useRouter();
const searchParams = useSearchParams();
const [query, setQuery] = useState(searchParams.get('query') || '');
const handleSearch = () => {
if (!query.trim()) return router.push('?');
const params = new URLSearchParams(searchParams.toString());
params.set('query', query.trim());
if (params.has('page')) params.delete('page');
router.push(`?${params.toString()}`);
};
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
e.preventDefault();
handleSearch();
}
};
return (
<div className="relative flex items-center h-8 text-sm border border-border rounded-md bg-input">
<input type="text" name="query" className="outline-none px-2" placeholder={placeholder} onKeyDown={handleKeyDown} onChange={(e) => setQuery(e.target.value)} />
<button type="submit" className="border border-border mx-auto mr-1 p-1 cursor-pointer rounded-md hover:bg-sidebar/10 transition-colors duration-300" onClick={handleSearch}>
<SearchIcon size={12} className={'text-foreground/80'} />
</button>
</div>
);
}
17 Replies
Do you have a loading.tsx file at the same level than your page.tsx that’s awaiting
searchParams
?Alaskan MalamuteOP
I have a loading.tsx at the same level yes but when pushing search params it stays on the old page until the result of getCitizens is awaited.
-- dashboard/citizens/loading.tsx
export default async function CitizensPage({ searchParams }: { searchParams: Promise<{ query?: string; page?: number }> }) {
await searchParams;
return (
<>
<PageHeader>
<PageHeader.Title>Personen</PageHeader.Title>
<PageHeader.Buttons>
<SearchQueryInput placeholder={'Person suchen...'} />
</PageHeader.Buttons>
</PageHeader>
<Card className={'p-4 h-full'}>
<LoadingSpinner />
</Card>
</>
);
}
It works on the first page load.
@Alaskan Malamute I have a loading.tsx at the same level yes but when pushing search params it stays on the old page until the result of getCitizens is awaited.
-- dashboard/citizens/loading.tsx
export default async function CitizensPage({ searchParams }: { searchParams: Promise<{ query?: string; page?: number }> }) {
await searchParams;
return (
<>
<PageHeader>
<PageHeader.Title>Personen</PageHeader.Title>
<PageHeader.Buttons>
<SearchQueryInput placeholder={'Person suchen...'} />
</PageHeader.Buttons>
</PageHeader>
<Card className={'p-4 h-full'}>
<LoadingSpinner />
</Card>
</>
);
}
Wait you don’t need to await search params here, this is supposed to be a static shell that’s gonna be displayed while your page suspends due to the async tasks going on
Alaskan MalamuteOP
Ah ok i miss understood you
Have you thought about moving the search input block into your
/dashboard/citizens/layout.tsx
// /dashboard/citizens/layout.tsx
export default async function CitizensLayout({ children }: { children : ReactNode }) {
// ...
return (
<>
<PageHeader>
<PageHeader.Title>Personen</PageHeader.Title>
<PageHeader.Buttons>
<SearchQueryInput placeholder={'Person suchen...'} />
</PageHeader.Buttons>
</PageHeader>
{ children }
</>
);
}
// -----------------------------
// /dashboard/citizens/page.tsx
export default async function CitizensPage({ searchParams }: { searchParams: Promise<{ query?: string; page?: number }> }) {
const citizens = await getCitizens({ searchParams: await searchParams });
return (
<Card className={'p-4'}>
<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Alias</TableHead>
<TableHead>Tags</TableHead>
<TableHead>Waffenschein gültig bis</TableHead>
<TableHead>Telefonnummer</TableHead>
<TableHead>Geschlecht</TableHead>
<TableHead>Geburtsdatum</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{citizens.map((citizen) => (
<TableRow key={citizen.id}>
</TableRow>
))}
</TableBody>
</Table>
</Card>
);
}
// -----------------------------
// /dashboard/citizens/loading.tsx
export default async function Loading() {
return (
<Card className={'p-4 h-full'}>
<LoadingSpinner />
</Card>
);
}
*loading.tsx *will replace the contents on page.tsx while it's fetching the data for the new
searchParams
. And since <SearchQueryInput placeholder={'Person suchen...'} />
is now in the Layout this will persist and keep its own state.Alaskan MalamuteOP
The problem is still that that when i enter the search input the site still keeps the old state until the callback of getCitizens is back.
Can I see your folder structure?
Alaskan MalamuteOP
Mmm that folder structure works for me, maybe you are trying to do something I do not fully get. For me my page suspends when I change the params and searchParams.
Alaskan MalamuteOP
How to you set your searchparams
I'm just using <Link /> component. But AFAIK both <Link> and router.push use the same APIs under the hood.
Btw, that's not a real project I dump code and stuff to try on there.
Btw, that's not a real project I dump code and stuff to try on there.
Alaskan MalamuteOP
Can you maybe show your contents
[Here's the repo](https://github.com/llanesluis/template/tree/test-hacky-dashboard)
Have in mind some things might look messy, and not sure this approach can work for your specific use-case
Alaskan MalamuteOP
It works for you because you also switch the route using the slug