Giới thiệu vấn đề cache trong TanStack Query

TanStack Query (React Query) quản lý trạng thái server dữ liệu. Khi dashboard hiển thị danh sách sản phẩm, đơn hàng, người dùng, mỗi request có thể gây tải mạng không cần thiết nếu cache không được cấu hình đúng.

Cấu hình thời gian sống (staleTime) và thời gian giữ (cacheTime)

Thiết lập staleTime dài cho dữ liệu ít thay đổi (ví dụ danh mục sản phẩm). Thiết lập cacheTime ngắn cho dữ liệu thay đổi nhanh (giỏ hàng).

import { useQuery } from '@tanstack/react-query';

const useCategories = () => {
  return useQuery(['categories'], fetchCategories, {
    staleTime: 1000 * 60 * 60, // 1 giờ
    cacheTime: 1000 * 60 * 30, // 30 phút
    refetchOnWindowFocus: false,
  });
};

Giải thích

  • staleTime: dữ liệu không được đánh dấu là stale trong khoảng thời gian này, tránh refetch tự động.
  • cacheTime: thời gian giữ cache sau khi không còn component nào sử dụng.
  • refetchOnWindowFocus: tắt để tránh refetch khi người dùng chuyển tab.

Chiến lược invalidation cho dữ liệu mutable

Đối với giỏ hàng, mỗi thao tác (thêm, xóa, cập nhật) nên gọi queryClient.invalidateQueries để làm mới dữ liệu.

import { useMutation, useQueryClient } from '@tanstack/react-query';

const useAddToCart = () => {
  const queryClient = useQueryClient();
  return useMutation(addItemToCart, {
    onSuccess: () => {
      queryClient.invalidateQueries(['cart']);
    },
  });
};

Batch invalidation

Khi cập nhật nhiều trường (status, payment), dùng queryClient.invalidateQueries({ predicate: q => q.queryKey[0] === 'orders' }) để tránh gọi nhiều lần.

Prefetch dữ liệu cho trang chi tiết

Trước khi người dùng chuyển sang trang chi tiết sản phẩm, gọi queryClient.prefetchQuery để tải dữ liệu trong nền.

import { useQueryClient } from '@tanstack/react-query';

const prefetchProduct = async (productId) => {
  const queryClient = useQueryClient();
  await queryClient.prefetchQuery(['product', productId], () => fetchProduct(productId), {
    staleTime: 1000 * 60 * 5,
  });
};

Quản lý lỗi và fallback UI

Sử dụng onError để ghi log và hiển thị UI dự phòng, tránh trạng thái treo khi server trả về lỗi.

const { data, error, isLoading } = useQuery(['orders'], fetchOrders, {
  onError: (err) => {
    console.error('Fetch orders failed', err);
  },
});

Kết luận

Áp dụng staleTime, cacheTime, invalidate và prefetch giúp giảm tải API, tăng tốc UI Dashboard Ecommerce. Tham khảo khóa học "[Full Course] Ecommerce Dashboard Fullstack Clone" tại đây.