I'm using Next.js and React Query for SSR.
Everything is fine until re-entering the exact dynamic route(e.g. domain/support/guide/faq/[id]
).
The expected behavior is rendered query data without fetching as I used SSR for the component.
Please check my code
// PAGE, I pass the query string to the <FAQContent /> Component
export default function FAQDetailPage({ id }: { id: string }) {
return <FAQContent id={id} category={"faq"} />;
}
export async function getServerSideProps({
query: { id },
}: {
query: { id: string };
}) {
const queryClient = new QueryClient();
try {
await queryClient.prefetchQuery(["support", "faq", id], () => {
return sendRequest({
method: "get",
path: `/article/${id}`,
apiType: "Contents",
});
});
} catch (e) {
return {
redirect: {
destination: "/",
permanent: false,
},
};
}
const dehydratedQueryClient = dehydrate(queryClient);
const targetQuery = dehydratedQueryClient.queries[0];
const targetQueryState = targetQuery.state as any;
return {
props: {
dehydratedState: {
...dehydratedQueryClient,
queries: [
{
...dehydrate(queryClient).queries[0],
state: {
...targetQueryState,
data: targetQueryState.data.data,
},
},
],
},
id,
},
};
}
// Get id and category from the page, and pass to <SupportBoardContent />
export default function FAQContent({
id,
category,
}: {
id: string;
category: string;
}) {
return <SupportBoardContent id={id} category={category} />;
}
// Here is the component where hydrate the dehydrated query
export default function SupportBoardContent({
id,
category,
}: {
id: string;
category: string;
}) {
const router = useRouter();
const { pathname } = router;
// This is a hook for useQuery.
const {
data: boardContent,
ResponseHandler: ResponseHandlerOfGetBoardContent,
} = SUPPORT_QUERY.useGetBoardContent({
id,
category,
});
const { title, contents, memo, videoURL, articleType } =
boardContent?.targetArticle || {};
return (
<SupportLayout>
{boardContent && (
<CommonStyled.mainContainer>
<SupportBreadcrumb title={title} />
<BoardPageTitle titleStyle="default">
{getArticleBoardTypeString(articleType)}
</BoardPageTitle>
<BoardContent
title={title}
annotation={memo}
desc={contents}
videoURL={videoURL}
/>
</CommonStyled.mainContainer>
)}
</SupportLayout>
);
}
When the component mounts on its first, nothings wrong. Everything works I expected. However, There is a <SupportBreadCrumb />
Component.
In <SupportBreadCrumb />
, I use Link
from Next/link
. Whenever I tries to enter the same page with Link
Component, the data
from useQueryHook
is undefined.
id
is not undefined, category
is not undefined. BUT data is undefined.
I'm struggling with this problem for hours and need some guidance about it.
From this post, I want to know about:
Does using Link
from Next.js is not a proper behavior when using SSR? By using Link
, I heard that rendering of very first page is SSR condition, but does CSR afterword.
I want to know why useQuery
doesn't fetch data, even id
is ready for parameter.
Answer to your first question:
A link component in SSR always calls the getServerSideProps
function, and this cannot be prevented. (It won't call when shallow routing is used).
A trick is to check whether the request to getServerSideProps
is from a client side navigation and if so return an empty object for props and handle data fetching on the client.
Your second question :
I am not sure what's going on and why your useQuery
hook fails to fetch data, but your hydrate/dehydrate logic in your getServerSideProps
is strange to me and I did not find any Hydrate component.
Maybe this is what is causing your problems.
I wrote a blog post about using react-query and next.js SSR and I hope it can help you.