Next.js App Router - client-side and server-side component with hydration boundary #6267
Replies: 2 comments 10 replies
-
So far, the best option that I have come up with is this |
Beta Was this translation helpful? Give feedback.
-
So my case here can be represented simpler like that: we have a server component that renders the client component that uses under-the-hood query, directly or wrapped with a server component that prefetches the query and wraps it inside HydrationBoundary like that: export default async function ServerComponent() {
<User /> // client component
<UserHydrated /> // same component, but wrapped in a hydration boundary
} User: 'use client';
import { getUser } from '@/api/get-user';
import { useQuery } from '@tanstack/react-query';
export const User = () => {
const { data: user } = useQuery({
queryKey: ['user'],
queryFn: getUser,
});
return (
<h1 className="text-6xl font-bold text-center mb-8">
Bro {user?.name} you are logged in!
</h1>
);
}; UserHydrated: import { getUser } from '@/api/get-user';
import {
HydrationBoundary,
QueryClient,
dehydrate,
} from '@tanstack/react-query';
import { User } from './user';
export const UserHydrated = async () => {
const queryClient = new QueryClient();
await queryClient.prefetchQuery({
queryKey: ['user'],
queryFn: getUser,
});
return (
<HydrationBoundary state={dehydrate(queryClient)}>
<User />
</HydrationBoundary>
);
}; And with that setup, SSR does not work, and both components render on the client. But if I comment out raw client component then SSR works fine for UserHydrated. Is that how things should work that you must wrap all prefetched queries with HydrationBoundary or it's possible to use SSR for both when HydrationBoundary was used near the client component, or maybe some work around it? |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I want only private pages like "profile" to fetch users using SSR so that public pages will stay static. I have a "header" component that renders on every page so I put it inside the root layout. But I want a prefetch query on certain pages like "profile" using SSR. The problem is that if I have a component with the query outside of the "hydration boundary" and a component inside the "hydration boundary" both are start running on the client.
Root layout:
Providers:
Header:
Profile page:
Profile:
Everything works fine if I put "header" separately on each page like that:
export default async function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html lang="en"> <body className={inter.className}> <Providers> - <Header /> {children} ...
export default async function HomePage() { return ( <> + <Header/> <main className="flex min-h-screen flex-col items-center justify-between p-24"> <div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex"> <p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30"> Get started by editing ...
export default async function ProfilePage() { const queryClient = new QueryClient(); await queryClient.prefetchQuery({ queryKey: ['user'], queryFn: getUser, }); return ( <HydrationBoundary state={dehydrate(queryClient)}> + <Header /> <Profile /> </HydrationBoundary> ); }
the problem is that the header was using a "user" query and was outside HydrationBoundary. Is there any way to work around it? It feels tedious/wrong to add the "header" to each page or page layout if I need it on every page. I'd be grateful for your help!
Beta Was this translation helpful? Give feedback.
All reactions