为什么我们需要 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));
}, []);
这种写法虽然直观,但随着应用变大,我们会面临一系列问题:
- 重复代码:每个请求都要写一遍 loading/error 逻辑。
- 缓存失效:如何处理缓存?何时重新获取?
- 竞态条件:组件卸载了请求还在跑怎么办?
- 后台更新:用户切换窗口回来后,数据是否需要刷新?
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。