Next.js App Router pattern với React Query: Server Components fetch data và dehydrate cache, Client Components nhận hydrated cache — không có loading flash.
Pattern đầy đủ:
- Tạo
getQueryClient()factory vớicache()từ React để mỗi request server có QueryClient riêng (tránh data leak giữa users). - Server Component:
const queryClient = getQueryClient(); await queryClient.prefetchQuery({ queryKey: ['posts'], queryFn: fetchPosts }); return <HydrationBoundary state={dehydrate(queryClient)}><PostList /></HydrationBoundary>. - Client Component dùng
useQuerybình thường — nhận data từ hydrated cache ngay, không request thêm nếu data còn fresh
Streaming hydration: có thể dùng với Suspense để stream từng phần page.
RSC considerations: không thể dùng React Query hooks trong RSC (chỉ là async functions) — hooks chỉ trong Client Components.
Nên prefetch ở server những gì quan trọng cho initial render, lazy load phần ít quan trọng hơn ở client.
Pitfall: nếu không dùng cache() cho QueryClient factory, server-side QueryClient sẽ được share giữa requests → data leaking.