跳转到内容

Next.js React Query

来自代码酷

Next.js React Query[编辑 | 编辑源代码]

介绍[编辑 | 编辑源代码]

React Query 是一个用于管理服务器状态的强大库,专为 React 应用设计。在 Next.js 中,它能够高效地处理数据获取、缓存、同步和更新,同时减少样板代码。React Query 的核心优势在于其智能缓存机制和自动后台刷新功能,使得开发者可以专注于业务逻辑而非数据管理细节。

在 Next.js 中,React Query 通常与静态生成(SSG)、服务器端渲染(SSR)或客户端渲染(CSR)结合使用,提供灵活的数据加载策略。它支持:

  • 自动缓存和重复请求去重
  • 后台数据刷新
  • 分页和无限加载优化
  • 错误处理和重试机制

核心概念[编辑 | 编辑源代码]

QueryClient 与 QueryClientProvider[编辑 | 编辑源代码]

React Query 的核心是 QueryClient,它管理所有查询的状态和缓存。在 Next.js 中,通常需要在应用顶层初始化并注入它:

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient();

function App({ Component, pageProps }) {
  return (
    <QueryClientProvider client={queryClient}>
      <Component {...pageProps} />
    </QueryClientProvider>
  );
}

基本查询(useQuery)[编辑 | 编辑源代码]

useQuery 是用于获取数据的核心钩子。以下是一个获取用户数据的示例:

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

function UserProfile({ userId }) {
  const { data, isLoading, error } = useQuery({
    queryKey: ['user', userId], // 唯一标识查询的键
    queryFn: () => fetch(`/api/users/${userId}`).then(res => res.json()),
    staleTime: 5000, // 数据在5秒后视为过期
  });

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return <div>{data.name}</div>;
}

修改数据(useMutation)[编辑 | 编辑源代码]

useMutation 用于创建、更新或删除数据:

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

function AddUser() {
  const mutation = useMutation({
    mutationFn: (newUser) => fetch('/api/users', {
      method: 'POST',
      body: JSON.stringify(newUser),
    }),
    onSuccess: () => {
      // 用户添加成功后的操作
    },
  });

  return (
    <button onClick={() => mutation.mutate({ name: 'New User' })}>
      Add User
    </button>
  );
}

高级特性[编辑 | 编辑源代码]

预加载数据[编辑 | 编辑源代码]

在 Next.js 中,可以在页面加载前预取数据:

// 在 getServerSideProps 或 getStaticProps 中
export async function getServerSideProps() {
  const queryClient = new QueryClient();
  await queryClient.prefetchQuery({
    queryKey: ['posts'],
    queryFn: fetchPosts,
  });

  return { props: { dehydratedState: dehydrate(queryClient) } };
}

// 在客户端通过 useQuery 直接使用预加载的数据
const { data } = useQuery({ queryKey: ['posts'], queryFn: fetchPosts });

无限查询[编辑 | 编辑源代码]

对于分页或无限加载的场景:

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

function Posts() {
  const {
    data,
    fetchNextPage,
    hasNextPage,
  } = useInfiniteQuery({
    queryKey: ['posts'],
    queryFn: ({ pageParam = 1 }) => fetchPosts(pageParam),
    getNextPageParam: (lastPage) => lastPage.nextPage,
  });

  return (
    <>
      {data.pages.map((page) => (
        page.posts.map(post => <Post key={post.id} {...post} />)
      ))}
      <button onClick={() => fetchNextPage()}>
        {hasNextPage ? 'Load More' : 'Nothing more to load'}
      </button>
    </>
  );
}

实际案例[编辑 | 编辑源代码]

电商产品列表[编辑 | 编辑源代码]

假设构建一个电商网站的产品列表页:

function ProductList() {
  const { data: products, isLoading } = useQuery({
    queryKey: ['products'],
    queryFn: () => fetch('/api/products').then(res => res.json()),
    // 产品数据每60秒自动刷新
    staleTime: 60000,
  });

  const { mutate: addToCart } = useMutation({
    mutationFn: (productId) => addProductToCart(productId),
    onSuccess: () => showToast('Added to cart!'),
  });

  if (isLoading) return <Spinner />;

  return (
    <div className="grid">
      {products.map(product => (
        <ProductCard 
          key={product.id} 
          product={product}
          onAddToCart={() => addToCart(product.id)}
        />
      ))}
    </div>
  );
}

性能优化[编辑 | 编辑源代码]

React Query 提供多种优化选项:

1. 选择性重渲染:只有数据变化的组件会重新渲染 2. 智能缓存:相同查询的多个实例共享缓存 3. 请求合并:同时发起的相同请求会自动合并 4. 垃圾回收:未使用的缓存数据会被自动清理

常见问题[编辑 | 编辑源代码]

与 Next.js 缓存如何协作?[编辑 | 编辑源代码]

React Query 的客户端缓存可以与 Next.js 的服务器端缓存(如 getStaticProps)完美配合。初始加载使用服务器数据,后续导航使用客户端缓存。

如何处理认证?[编辑 | 编辑源代码]

可以通过配置 QueryClient 的默认选项全局处理认证错误:

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      onError: (error) => {
        if (error.status === 401) redirectToLogin();
      },
    },
  },
});

总结[编辑 | 编辑源代码]

React Query 为 Next.js 应用提供了专业的数据管理解决方案,具有以下优势:

  • 减少约 80% 的数据管理样板代码
  • 内置智能缓存和性能优化
  • 与 Next.js 的渲染模式深度集成
  • 丰富的开发者工具支持

通过合理配置,可以构建出既快速又可靠的数据驱动型应用。