TanStack Query:前端数据获取的终极解决方案

前端开发

为什么我们需要 TanStack Query?

在传统的 React 开发中,我们经常使用 useEffect 配合 useState 来获取数据:

const [data, setData] = useState(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);

useEffect(() => {
  fetch('/api/data')
    .then(res => res.json())
    .then(setData)
    .catch(setError)
    .finally(() => setIsLoading(false));
}, []);

这种写法虽然直观,但随着应用变大,我们会面临一系列问题:

  1. 重复代码:每个请求都要写一遍 loading/error 逻辑。
  2. 缓存失效:如何处理缓存?何时重新获取?
  3. 竞态条件:组件卸载了请求还在跑怎么办?
  4. 后台更新:用户切换窗口回来后,数据是否需要刷新?

TanStack Query (原 React Query) 就是为了解决这些问题而生的。它不仅仅是一个数据获取库,更是一个异步状态管理器

快速入门

首先安装依赖:

npm install @tanstack/react-query

1. 配置 QueryClientProvider

在应用的顶层包裹 QueryClientProvider

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

const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <Todos />
    </QueryClientProvider>
  );
}

2. 使用 useQuery 获取数据

useQuery 是最常用的 Hook,它接收两个核心参数:

  • queryKey: 唯一标识这个请求的数组,用于缓存。
  • queryFn: 实际执行请求的异步函数。
import { useQuery } from '@tanstack/react-query';

function Todos() {
  const { isPending, error, data } = useQuery({
    queryKey: ['todos'],
    queryFn: () =>
      fetch('https://jsonplaceholder.typicode.com/todos').then((res) =>
        res.json(),
      ),
  });

  if (isPending) return '加载中...';

  if (error) return '出错了: ' + error.message;

  return (
    <ul>
      {data.map((todo) => (
        <li key={todo.id}>{todo.title}</li>
      ))}
    </ul>
  );
}

核心特性解析

自动缓存与去重

当你多次使用相同的 queryKey 时,TanStack Query 会自动复用缓存中的数据,避免重复请求。

窗口聚焦重新获取 (Window Focus Refetching)

默认情况下,当用户切换浏览器标签页并返回时,TanStack Query 会自动在后台刷新数据,确保用户看到的是最新的。

乐观更新 (Optimistic Updates)

在执行修改操作(如点赞、评论)时,可以先更新 UI,再发送请求。如果请求失败,再回滚状态。这能提供极致的用户体验。

总结

TanStack Query 极大地简化了服务端状态的管理。它让我们从繁琐的 useEffect 和状态同步中解放出来,专注于业务逻辑。如果你还在手动管理 API 请求状态,强烈建议尝试一下 TanStack Query。