Best practice for refetching?
Answered
Selkirk Rex posted this in #help-forum
Selkirk RexOP
Currently have a setup where I have a server component as page.tsx where I call the necessary data, and pass to a client component. Similar to this:
OverviewPage.tsx would be 'use client'.
What are the best practices for refetching from the client component? Should I be using revalidateTag or am I going up the wrong tree? I don't want to do a reload of the page, as I would like to have UI implying that it's fetching?
export const dynamic = 'force-dynamic';
import OverviewPage from 'app/[lng]/overview/OverviewPage';
import { getMeltStations } from 'app/utils/getMeltStations';
const Page = async () => {
const meltStations = await getMeltStations();
return <OverviewPage meltStations={meltStations} />;
};
export default Page;OverviewPage.tsx would be 'use client'.
What are the best practices for refetching from the client component? Should I be using revalidateTag or am I going up the wrong tree? I don't want to do a reload of the page, as I would like to have UI implying that it's fetching?
Answered by Selkirk Rex
Updating the refetch function by adding 'router.refresh()' solved the issue:
const onRefetchProjects = useCallback(async () => {
await revalidateBuildProjects();
setFetchDate(new Date());
router.refresh();
}, [router]);4 Replies
Asian black bear
Reloading the page is the most idiomatic and convenient way to do this without unnecessary overhead. If you for some reason insist on advanced client-side refetching capabilities you'd have to use react-query, prefetch server-side and initialise the data in the client component while also passing on a fetcher accessing a public endpoint to refetch the data. At this point you should really evaluate whether you REALLY need all of this just because you want a SPA feel despite having a SSRed MPA.
Selkirk RexOP
@Asian black bear I've tried to solve this using revalidateTag. However, I've encountered something that is baffling me, I wonder if you have any insight?
server component - page.tsx:
I then have an action in action.ts:
In my client component I have filters that when updated trigger this:
server component - page.tsx:
export const dynamic = 'force-dynamic';
const initialParams: GetBuildProjectsParams = {
pageNumber: 1,
pageSize: 25,
sortBy: 'createdAt',
sortOrder: SortOrder.DESC,
};
const Page = async ({ searchParams, params: { lng } }: PageProps) => {
const params: GetBuildProjectsParams = {
pageNumber: parseInt(searchParams.pageNumber) || initialParams.pageNumber,
pageSize: parseInt(searchParams.pageSize) || initialParams.pageSize,
sortOrder: Object.values<string>(SortOrder).includes(searchParams.sortOrder)
? (searchParams.sortOrder as SortOrder)
: initialParams.sortOrder,
name: searchParams.name || undefined,
};
const querySearchParams = new URLSearchParams();
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined && canStringify(value)) {
querySearchParams.append(key, value.toString());
}
});
const query = querySearchParams.toString();
const res = await fetch(`http://localhost:3000/api/build-projects?${query}`, {
next: { tags: ['buildProjects'] },
});
const buildProjects = (await res.json()) as GetBuildProjectsResponse;
console.log('FETCHED RESULTS:::::::::::');
console.log(buildProjects);
return <BuildFilesPage {...{ buildProjects, params, lng }} />;
};
export default Page;I then have an action in action.ts:
'use actions'
import { revalidateTag } from 'next/cache';
export async function revalidateBuildProjects() {
revalidateTag('buildProjects');
}In my client component I have filters that when updated trigger this:
const onRefetchProjects = useCallback(async () => {
console.log('REVALIDATE CLIENT');
await revalidateBuildProjects();
setFetchDate(new Date());
}, []);Here are my logs:
Initial render:
After updating filters and triggering revalidateTag()
The above logs clearly show that the server is fetching properly but not updating client. I have a button that triggers the onRefetchProjects function again, after this, the data is correctly fetched and rendered in client.
Do you have any idea what's happening?
Initial render:
yarn run v1.22.22
$ next dev
▲ Next.js 14.2.5
- Local: http://localhost:3000
- Environments: .env
✓ Starting...
✓ Ready in 1719ms
✓ Compiled /middleware in 461ms (931 modules)
○ Compiling /[lng]/test ...
✓ Compiled /[lng]/test in 5.1s (5924 modules)
○ Compiling /api/build-projects ...
✓ Compiled /api/build-projects in 1510ms (3552 modules)
GET /api/build-projects?pageNumber=1&pageSize=25&sortBy=createdAt&sortOrder=desc 200 in 1682ms
FETCHED RESULTS:::::::::::
{
totalCount: 1,
result: [
{
id: 'a5976cb1-2120-4ed0-80c5-29ac77d2be21',
externalId: 'fa7c2cce-d96b-4a14-a623-be434a831efb',
activeRevision: 1,
obsoleted: false,
createdAt: '2024-08-06T15:15:59.513Z',
deletedAt: null,
build: [Object]
}
]
}
GET /enUS/test 200 in 7652msAfter updating filters and triggering revalidateTag()
GET /api/build-projects?pageNumber=1&pageSize=25&sortBy=createdAt&sortOrder=desc&name=Seb 200 in 30ms
GET /api/build-projects?pageNumber=1&pageSize=25&sortBy=createdAt&sortOrder=desc&name=Seb 200 in 24ms
FETCHED RESULTS:::::::::::
{ totalCount: 0, result: [] }
POST /enUS/test?pageNumber=1&pageSize=25&sortBy=createdAt&sortOrder=desc&name=Seb 200 in 223ms
FETCHED RESULTS:::::::::::
{ totalCount: 0, result: [] }The above logs clearly show that the server is fetching properly but not updating client. I have a button that triggers the onRefetchProjects function again, after this, the data is correctly fetched and rendered in client.
FETCHED RESULTS:::::::::::
{ totalCount: 0, result: [] }
POST /enUS/test?pageNumber=1&pageSize=25&sortBy=createdAt&sortOrder=desc&name=Seb 200 in 50ms Do you have any idea what's happening?
Selkirk RexOP
Updating the refetch function by adding 'router.refresh()' solved the issue:
const onRefetchProjects = useCallback(async () => {
await revalidateBuildProjects();
setFetchDate(new Date());
router.refresh();
}, [router]);Answer