TanStack Query v6: Data fetching patterns mới
Khám phá những thay đổi quan trọng trong TanStack Query v6 — từ suspense queries, streaming, đến prefetching patterns mới cho Next.js App Router.
TanStack Query (trước đây React Query) vừa release v6 với nhiều thay đổi lớn. Nếu bạn đang dùng v5, đây là những patterns mới cần biết — và cách kết hợp với Next.js App Router.
Tại sao vẫn cần TanStack Query khi có RSC?
Câu hỏi này hay được đặt ra. RSC fetch data trên server tuyệt vời, nhưng bạn vẫn cần TanStack Query cho:
- Client-side mutations với optimistic updates, retry, rollback
- Real-time polling và background refetching
- Infinite scrolling và pagination
- Offline support và cache persistence
- Dependent queries — query B chờ result của query A
v6: Suspense-first API
TanStack Query v6 đặt Suspense làm first-class citizen. useSuspenseQuery trở thành recommended default:
"use client";
import { useSuspenseQuery } from "@tanstack/react-query";
function ArticleList({ categorySlug }: { categorySlug: string }) {
// Không cần check isLoading, isError — Suspense handle hết
const { data: articles } = useSuspenseQuery({
queryKey: ["articles", categorySlug],
queryFn: () =>
fetch(`/api/v1/posts?category=${categorySlug}`).then((r) =>
r.json()
),
staleTime: 5 * 60 * 1000, // 5 minutes
});
return (
<div className="grid gap-4">
{articles.posts.map((article) => (
<ArticleCard key={article.id} article={article} />
))}
</div>
);
}
// Wrap trong Suspense boundary
export function ArticleSection({ categorySlug }) {
return (
<Suspense fallback={<ArticleListSkeleton />}>
<ArticleList categorySlug={categorySlug} />
</Suspense>
);
}
Với useSuspenseQuery, data luôn defined — không cần null checks. Loading và error state handled bởi Suspense và Error Boundary.
Prefetching trong Server Components
Pattern mạnh nhất: prefetch data trong Server Component, hydrate vào client:
// app/articles/page.tsx — Server Component
import {
dehydrate,
HydrationBoundary,
QueryClient,
} from "@tanstack/react-query";
import { ArticleSection } from "@/components/ArticleSection";
export default async function ArticlesPage() {
const queryClient = new QueryClient();
await queryClient.prefetchQuery({
queryKey: ["articles", "all"],
queryFn: () =>
fetch("http://localhost:3000/api/v1/posts").then((r) => r.json()),
});
return (
<HydrationBoundary state={dehydrate(queryClient)}>
<ArticleSection categorySlug="all" />
</HydrationBoundary>
);
}
Data fetch trên server (fast), hydrate vào client cache (instant). Client component có data ngay mà không cần loading state.
Infinite Queries cải tiến
v6 cải thiện useSuspenseInfiniteQuery với better TypeScript support và maxPages option để limit memory usage. Kết hợp với IntersectionObserver cho infinite scroll smooth.
Mutation patterns mới
Optimistic updates dễ hơn với mutation scope. Retry logic configurable per-mutation. Mutation filters cho phép cancel/invalidate mutations theo pattern.
Migration từ v5
Breaking changes ít hơn so với v4→v5. Chính:
- useQuery vẫn hoạt động nhưng recommend chuyển sang useSuspenseQuery
- cacheTime đã renamed thành gcTime từ v5, v6 remove alias cũ
- Default staleTime giờ là 0 (fetch mỗi lần mount)
- QueryClientProvider vẫn required cho client components
Kết luận
TanStack Query v6 + Next.js App Router là combo mạnh mẽ. Dùng RSC cho initial data fetch, TanStack Query cho client-side interactivity. Suspense-first API giúp code sạch hơn, ít boilerplate hơn. Nếu bạn đang làm app cần dynamic data beyond static rendering, TanStack Query vẫn là thư viện data fetching tốt nhất.
Admin
Bình luận (0)
Đăng nhập để bình luận
Chưa có bình luận nào. Hãy là người đầu tiên!