介绍一个🔥火热的React 应用状态管理库

npm 周下载量 :超过 170 万次(截至 2023 年底),这个数字在持续快速增长

GitHub Stars :超过 38k

在用的知名公司:Netflix, Facebook, Amazon, Microsoft, Airbnb


中文文档

官方英文文档

🔹 What(它是什么)

React Query 是一个 专门用来管理「服务端数据」的库

  • React 自身只提供了 useStateuseEffect 等 Hook,但它们适合处理本地 UI 状态(比如按钮是否展开、输入框值)。

  • 但是一旦涉及 远程数据(API 请求),就会出现很多问题:加载状态、错误处理、缓存、刷新、并发请求覆盖......这些在传统写法里非常复杂。

  • React Query 就是帮你把这一堆麻烦的逻辑"打包"成几个简单的 Hook,比如:

    • useQuery → 读数据
    • useMutation → 写数据(增删改)

🔹 Why(为什么要用它)

传统 useEffect + useState 写法的问题:

  1. 需要手写 loading / error / data 三套状态,还要同步管理。
  2. 请求竞态问题:比如快速切换用户详情页面时,旧请求覆盖新请求,页面展示错数据。
  3. 缓存难管理:离开页面再回来,要不要重新请求?数据是否过时?
  4. 代码冗长、容易出错,还经常要配合 Redux/Context 去做全局数据管理,复杂度爆炸。

👉 React Query 的价值:

  • 状态全自动(loading、error、success 状态都有现成的字段)
  • 缓存智能(Stale-While-Revalidate 策略,先给旧数据,再在后台刷新最新数据)
  • 请求时机自动化(窗口切回来、网络恢复、参数变化时都会自动刷新)
  • 声明式写法(只说"我要这份数据",不用手写各种状态切换逻辑)

🔹 How(怎么用)

  1. 初始化客户端(全局只需要一次)

    jsx 复制代码
    import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
    
    const queryClient = new QueryClient();
    
    function App() {
      return (
        <QueryClientProvider client={queryClient}>
          <MyComponent />
        </QueryClientProvider>
      );
    }
  2. 获取数据:useQuery

    jsx 复制代码
    import { useQuery } from '@tanstack/react-query';
    import axios from 'axios';
    
    function Todos() {
      const { data, isLoading, isError } = useQuery(
        ['todos'], // Query Key,用来标识这份数据
        () => axios.get('/api/todos').then(res => res.data) // Query Fn
      );
    
      if (isLoading) return <p>加载中...</p>;
      if (isError) return <p>出错了!</p>;
    
      return <ul>{data.map(todo => <li key={todo.id}>{todo.title}</li>)}</ul>;
    }
  3. 修改数据:useMutation

    jsx 复制代码
    import { useMutation, useQueryClient } from '@tanstack/react-query';
    import axios from 'axios';
    
    function AddTodo() {
      const queryClient = useQueryClient();
    
      const mutation = useMutation(
        newTodo => axios.post('/api/todos', newTodo),
        {
          onSuccess: () => {
            // 数据变更后,让 todos 的缓存失效,触发重新获取
            queryClient.invalidateQueries(['todos']);
          }
        }
      );
    
      return (
        <button onClick={() => mutation.mutate({ title: '新任务' })}>
          添加任务
        </button>
      );
    }

🔹 收获(你能得到什么)

  1. 开发效率提升:不用再手写一堆样板代码。

  2. 更好的用户体验:秒开页面(缓存先展示)、后台静默刷新、断网自动恢复。

  3. 数据永远新鲜:不用担心旧请求覆盖新请求,React Query 会自动帮你管。

  4. 更清晰的分工

    • 本地 UI 状态(开关、输入框等) → 继续用 useState 或 Redux/Zustand
    • 服务端数据(API) → 全交给 React Query

实战

基础实例:获取用户列表

jsx 复制代码
import { useQuery } from '@tanstack/react-query';
import { getUserList } from './api'; // 你的 API 函数

function UserList() {
  // 使用 useQuery Hook
  // ['users'] 是查询密钥,唯一标识这个查询
  const { data, isLoading, isError, error } = useQuery({
    queryKey: ['users'],
    queryFn: getUserList, // 一个返回 Promise 的函数,例如:() => fetch('/api/users').then(res => res.json())
  });

  if (isLoading) return <div>加载中...</div>;
  if (isError) return <div>出错啦! {error.message}</div>;

  return (
    <ul>
      {data?.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

带参数查询:获取单个用户详情

这个例子展示了如何依赖一个状态(如 userId)来发起查询。

jsx 复制代码
function UserProfile({ userId }) {
  // 查询密钥包含了 userId,当 userId 变化时,会自动发起新的请求
  const { data: user, isLoading } = useQuery({
    queryKey: ['user', userId], 
    queryFn: () => getUserById(userId),
    enabled: !!userId, // 只有 userId 存在时才启用查询
  });

  if (isLoading) return <div>加载用户信息...</div>;

  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
    </div>
  );
}

修改数据实例:创建新用户

这个例子展示了 useMutation 的典型用法,包括成功后使旧缓存失效。

jsx 复制代码
import { useMutation, useQueryClient } from '@tanstack/react-query';

function AddUser() {
  const queryClient = useQueryClient();
  const [name, setName] = useState('');

  // 定义 Mutation
  const createUserMutation = useMutation({
    mutationFn: (newUser) => createUserApi(newUser), // API 函数:POST /api/users
    onSuccess: () => {
      // ✅ 创建成功后,作废并重新获取 'users' 列表的查询
      queryClient.invalidateQueries({ queryKey: ['users'] });
      setName(''); // 清空输入框
      alert('用户创建成功!');
    },
    onError: (error) => {
      alert(`创建失败: ${error.message}`);
    }
  });

  const handleSubmit = (e) => {
    e.preventDefault();
    createUserMutation.mutate({ name: name }); // 触发 Mutation
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="输入用户名"
      />
      <button type="submit" disabled={createUserMutation.isLoading}>
        {createUserMutation.isLoading ? '创建中...' : '创建用户'}
      </button>
    </form>
  );
}

👉 总结一句: React Query 让你从「手动管理请求+状态的痛苦」中解放出来,把精力专注在业务逻辑和用户体验上。

相关推荐
字节逆旅8 小时前
CodeBuddy+Figma+MCP,我指挥AI写代码,老板夸我鱼摸得好
前端·人工智能·mcp
满分观察网友z8 小时前
JavaScript 趣味编程:从基础循环到函数式,解锁打印三角形的 N 种姿势
前端
Null1559 小时前
前端ZIP处理:JSZip vs fflate 全方位对比,让你的文件操作效率翻倍!
前端
Mishi9 小时前
前端踩坑日记-sass-resources-loader在Windows上遇到的问题
前端
Jacob02349 小时前
为什么现代 JavaScript 开发者正在远离回调与框架?
前端·javascript·前端框架
ZXT9 小时前
依赖管理
前端
ZXT9 小时前
vite & webpack
前端
yanlele9 小时前
前端面试第 77 期 - 2025.09.02 更新前端面试问题总结(15 道题)
前端·javascript·面试
徐小夕9 小时前
开源了一款基于 Vue 3 的高性能多维表格编辑器
前端·vue.js·github