T
TanStack13mo ago
foreign-sapphire

Passing initialData / placeholderData from the server

In the docs, the suggested way to use React-Query on Nextjs App router is by dehydrating and hydrating the query. For me, that's a bit too much (I am a newbie ✌🏻 - still working of my mental model of...well everything) and I tried a different approach and it seems to work fine. I just need to know if my approach is ok too, even if it's not the best. This is how I am doing it: In page.tsx (server component) I get the data 👇🏻
export default async function Page({
params,
searchParams,
}: {
params: { slug: string };
searchParams: { [key: string]: string | string[] | undefined };
}) {
const serverPosts = await postGetManyAction({
skip: 0,
take: 5,
});
// ...
export default async function Page({
params,
searchParams,
}: {
params: { slug: string };
searchParams: { [key: string]: string | string[] | undefined };
}) {
const serverPosts = await postGetManyAction({
skip: 0,
take: 5,
});
// ...
And pass to the component that needs it, and use it when calling my custom hook, where I use it like this:
const postGetManyActionOptions = ({
skip,
take,
}: {
take: number;
skip: number;
}) => {
return {
queryKey: ['PaginatedClient', { take }, { skip }],
queryFn: () => postGetManyAction({ take, skip }),
staleTime: 10 * 1000,
};
};

export const usePostGetManyQuery = ({
initialData,
take,
skip,
}: {
initialData: Awaited<TFetchResponse<TPost>>;
take: number;
skip: number;
}) => {

//...

return useQuery({
...postGetManyActionOptions({ take, skip }),
placeholderData: (previousData) =>
previousData ? previousData : initialData,
});
const postGetManyActionOptions = ({
skip,
take,
}: {
take: number;
skip: number;
}) => {
return {
queryKey: ['PaginatedClient', { take }, { skip }],
queryFn: () => postGetManyAction({ take, skip }),
staleTime: 10 * 1000,
};
};

export const usePostGetManyQuery = ({
initialData,
take,
skip,
}: {
initialData: Awaited<TFetchResponse<TPost>>;
take: number;
skip: number;
}) => {

//...

return useQuery({
...postGetManyActionOptions({ take, skip }),
placeholderData: (previousData) =>
previousData ? previousData : initialData,
});
1 Reply
foreign-sapphire
foreign-sapphireOP13mo ago
Please, notice that I am using the placeholderData property, not the initialData. Using it in the initialData property caused the initial data (the first page loaded in the server in the first snippet) to be shown whenever the query was fetching: for example, let's say we are on page 2 and click on "next" to go to page 3. while page 3 was being fetched, the initialData - which was page 1 - was put on the cache for it, creating a strage behaviour of the UI. Using placeholderData in the previous way solved the issue at the observer level instead of the cache level but seems to work fine. I understand that this has several drawbacks: - I have to pass initialData down - Don't know how to explain it ('cause I don't get how the other approach works), but I guess with this approach I could be duplicating fetches on the server, as two pages usin the same "initialData" will ask for it indepently, unaware that the data is already in the cace My question is: Is this method wrong? Thank you. Love RQ!

Did you find this page helpful?