网站首页 > 技术文章 正文
@tanstack/react-query(原 react-query)之所以被大厂广泛采用,核心在于它解决了前端开发中服务端状态管理的痛点,让数据请求、缓存、同步等操作变得极其简洁高效。它的 "好用" 主要体现在以下几个方面:
准备
pnpm add @tanstack/react-query
传统方式与react-query 方式
// 传统方式
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
let isMounted = true;
fetch('/api/users')
.then(res => res.json())
.then(data => { if (isMounted) setData(data); })
.catch(err => { if (isMounted) setError(err); })
.finally(() => { if (isMounted) setLoading(false); });
return () => { isMounted = false; }; // 解决竞态问题
}, []);
// react-query 方式
const { data, isLoading, error } = useQuery({
queryKey: ['users'], // 唯一标识,用于缓存
queryFn: () => fetch('/api/users').then(res => res.json())
});
集成到项目
import React from"react";
import {
QueryClient,
QueryClientProvider
} from"@tanstack/react-query";
import Layout from"@/Layout";
exportdefaultfunction App() {
// 创建 QueryClient 实例
const queryClient = new QueryClient();
return (
<QueryClientProvider client={queryClient}>
<Layout />
</QueryClientProvider>
);
}
useQuery 请求数据
useQuery 用于数据获取,支持自动缓存、重取和错误处理!
import React from"react";
import { useQuery } from"@tanstack/react-query";
import axios from"axios";
function fetchUser(userId: number) {
return axios.get(`/api/users`).then(res => res.data);
}
function User({ userId }: { userId: number }) {
const { data, isLoading, isError, error, refetch } = useQuery({
queryKey: ["user", userId], // 缓存 key
queryFn: () => fetchUser(userId),
// 数据在缓存中保持 1 分钟为新鲜,不会重复请求
staleTime: 1000 * 60,
// 数据缓存 5 分钟
cacheTime: 1000 * 60 * 5,
// 请求失败自动重试 2 次
retry: 2,
onError: (err) => {
console.error("获取用户数据失败:", err);
}
});
if (isLoading) return<div>加载中...</div>;
if (isError) return<div>出错了: {(error as Error).message}</div>;
return (
<div>
<h2>{data.name}</h2>
<p>Email: {data.email}</p>
<button onClick={() => refetch()}>手动触发重取</button>
</div>
);
}
突变与更新(useMutation)
useMutation 用于数据更新,如 POST 请求,支持乐观更新和回滚。
import React, { useState } from"react";
import {
useQuery,
useMutation,
useQueryClient
} from"@tanstack/react-query";
import axios from"axios";
// 模拟获取待办列表
const fetchTodos = () => axios.get("/api/todos").then(res => res.data);
// 模拟添加待办
const addTodo = (text: string) => axios.post("/api/todos", { text }).then(res => res.data);
exportfunction Todos() {
const queryClient = useQueryClient();
const [newText, setNewText] = useState("");
// 获取待办列表
const { data: todos = [] } = useQuery({ queryKey: ["todos"], queryFn: fetchTodos });
// useMutation 用于新增待办
const mutation = useMutation({
mutationFn: addTodo,
// 乐观更新
onMutate: async (text: string) => {
await queryClient.cancelQueries({ queryKey: ["todos"] });
const previousTodos = queryClient.getQueryData<any[]>(["todos"]);
// 立即更新缓存,显示新增项
queryClient.setQueryData(["todos"], [...(previousTodos || []), { id: Date.now(), text }]);
return { previousTodos }; // 返回上下文,用于失败回滚
},
// 出错时回滚
onError: (_err, _variables, context: any) => {
if (context?.previousTodos) {
queryClient.setQueryData(["todos"], context.previousTodos);
}
},
// 成功后刷新缓存
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ["todos"] });
}
});
return (
<div>
<h2>待办列表</h2>
<ul>
{todos.map(todo => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
<input value={newText} onChange={e => setNewText(e.target.value)} placeholder="新增" />
<button onClick={() => mutation.mutate(newText)}>添加</button>
</div>
);
}
并行/依赖查询
const userQuery = useQuery({
queryKey: ["user", userId],
queryFn: () => fetchUser(userId),
});
const postsQuery = useQuery({
queryKey: ["posts", userId],
queryFn: () => fetchPosts(userId),
});
如果需要依赖查询,则需要使用 enabled 属性!
const userQuery = useQuery({
queryKey: ["userByName", username],
queryFn: () => axios.get(`/api/users?username=${username}`).then(res => res.data),
});
const postsQuery = useQuery({
queryKey: ["posts", userQuery.data?.id],
queryFn: () => axios.get(`/api/users/${userQuery.data.id}/posts`).then(res => res.data),
// 只有当 userQuery 获取到 id 时才触发
enabled: !!userQuery.data?.id,
});
与框架无关,生态完善
tanstack 系列已支持 React、Vue、Svelte 等框架,API 设计一致,学习成本低。同时提供:
- 开发者工具(DevTools):可视化缓存状态、请求历史,方便调试
- 丰富的配置项:几乎所有行为都可自定义(缓存策略、重试机制、失效规则等)
- 类型安全:完美支持 TypeScript,减少类型错误
为什么大厂爱用?
对于复杂应用(如中台、电商、社交产品),服务端数据交互频繁,传统方式容易导致代码冗余、状态混乱、性能问题。react-query 用 "声明式" 的方式统一管理这些逻辑,让团队能更专注于业务,而非重复处理请求细节。
简单说:它让数据请求从 "手动挡" 变成了 "自动挡",这也是它被称为 "前端请求管理的终极方案" 的原因。
猜你喜欢
- 2025-09-18 react的filber架构_react的架构原理
- 2025-09-18 Vue和React迎来大融合!开发效率大提升
- 2025-09-18 七爪源码:如何在 React 中删除元素 OnClick
- 2025-09-18 通过番计时器实例学习 React 生命周期函数 componentDidMount
- 2025-09-18 React组件渲染优化:掌握key prop的3个实战技巧
- 2025-09-18 我找到了 Compiler 在低版本中使用的方法,它不再是 React 19 的专属
- 2025-09-18 JavaScript Proxy与Reflect实战经验顿悟
- 2025-09-18 React在开发中的常用结构以及功能详解
- 2025-09-18 2025开发React+Flask全栈应用最佳实践:10万+开发者验证终极指南
- 2025-09-18 快速上手React_快速上手 英文
- 最近发表
- 标签列表
-
- cmd/c (90)
- c++中::是什么意思 (84)
- 标签用于 (71)
- 主键只能有一个吗 (77)
- c#console.writeline不显示 (95)
- pythoncase语句 (88)
- es6includes (74)
- sqlset (76)
- apt-getinstall-y (100)
- node_modules怎么生成 (87)
- chromepost (71)
- flexdirection (73)
- c++int转char (80)
- mysqlany_value (79)
- static函数和普通函数 (84)
- el-date-picker开始日期早于结束日期 (76)
- js判断是否是json字符串 (75)
- c语言min函数头文件 (77)
- asynccallback (87)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- java (73)
- js数组插入 (83)
- mac安装java (72)
- 无效的列索引 (74)