掘金文章归档 · 第 62 篇 React 生态 1/5 react-query · useQuery

@tanstack/react-query 基础用法,三分钟入门

服务器数据当作全局状态,8 个 useQuery 场景 + useMutation

原文作者:随意_(掘金) | juejin.cn/post/7356778082823798810 | 发布于 2024-04-12 | 阅读 4,932 · 约 3 分钟

0介绍

@tanstack/react-query 是我们熟悉的 react-query 升级版,现在支持 vue 等,可以当做服务器数据的全局状态,主要写一下在 react 项目中 react-query 可简化很多逻辑处理,下面写一下基础用法,详情可查看文档。

1安装

npm i @tanstack/react-query

2app.tsx 引入并注册

import { createSyncStoragePersister } from "@tanstack/query-sync-storage-persister";
import { PersistQueryClientProvider } from "@tanstack/react-query-persist-client";

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      // 可增加全局配置
      refetchOnWindowFocus: false, // 窗口焦点重新获取
      gcTime: 1000 * 60 * 60 * 24, // 24 hours
    },
  },
});

const persister = createSyncStoragePersister({
  storage: window.localStorage,
});

function App() {
  return (
    <PersistQueryClientProvider client={queryClient} persistOptions={{ persister }}>
      <RouterProvider router={router} fallbackElement={<p>Loading...</p>} />
    </PersistQueryClientProvider>
  );
}

export default App;

下面自己安装组件库及路由即可,不再一一列举。可以封装 axios 请求,react-query 并不是一个 ajax 请求库,可以封装 fetch 或者 axios 用于请求,react-query 用于管理请求。

📌 定位:react-query 管"请求的状态与缓存",真正的网络请求仍由 axios / fetch 完成。

3useQuery 基础用法

场景 1:进入页面自动请求列表

如:我们在一个列表页面,进来会请求加载接口,我们给这个请求命名为 applist,默认会触发一次 apiApplicationList() 是我们封装的请求接口,他的返回值会给 applicationList,applicationList 初始化为 undefined,请注意初始值设置。我们列表直接渲染 applicationList 即可,applicationList 是一个 state。

// 获取列表
const { data: applicationList, refetch: listRefetch } = useQuery({
  queryKey: ["applist"],
  queryFn: () => apiApplicationList(),
});

场景 2:有 id 才查询

页面渲染有条件,如有 id 才查询,没有 id 不自动查询,enabled 可输入条件,控制是否初次触发。

const { data: applicationList, refetch: listRefetch } = useQuery({
  queryKey: ["applist"],
  queryFn: async () => {
    const data = await apiApplicationList();
    return data;
  },
  placeholderData: [], // 初始化的默认值,不设置则未 resolve 时返回 undefined
  enabled: !!id,
});

场景 3:传递参数

apiApplicationList({name:1}) 可主动传参。

const { data: applicationList, refetch: listRefetch } = useQuery({
  queryKey: ["applist"],
  queryFn: () => apiApplicationList({ name: 1 }),
  enabled: false,
});

场景 4:自定义 map 规则

接口返回数据不是我需要的,也可自定义 map 规则,applicationList 为我们处理后的数据,当然这种用法可以自定义自己请求前置的任何条件。

const { data: applicationList, refetch: listRefetch } = useQuery({
  queryKey: ["applist"],
  queryFn: async () => {
    const data = await apiApplicationList({});
    return data.map((item) => {
      return {
        ...item,
        id: item.application_id + 10,
      };
    });
  },
  enabled: false,
});

场景 5:操作后刷新列表

页面有个新增或者删除功能,操作成功后重新刷新接口,可主动触发 listRefetch(),重新请求拉取数据。

const reload = () => {
  listRefetch();
};

场景 6:获取请求状态

如列表加载完之前不允许任何操作,可以拿到这个接口的请求状态 isPending,根据 isPending 可以自己的逻辑处理。

const { data: applicationList, refetch: listRefetch, isPending } = useQuery({
  queryKey: ["applist"],
  queryFn: () => apiApplicationList({ name: 1 }),
  enabled: false,
});

场景 7:定时刷新接口

每隔一段时间需要刷新一次接口,比如 10S 刷新一次列表,refetchInterval 可实现。

const { data: applicationList, refetch: listRefetch } = useQuery({
  queryKey: ["applist"],
  queryFn: () => apiApplicationList(),
  refetchInterval: 10000,
});

场景 8:分页查询

查询条件变更则主动触发查询,避免 useEffect 频繁调用。我们可以借用 useImmer 来简化设置 state,当 listParams 变化后,重新自动请求接口。

// 初始化查询参数
const [listParams, setListParams] = useImmer({
  kb_id: paramsQuery.kbid || "",
  file_id: paramsQuery.fileid || "",
  page_num: 1,
  page_size: 9,
  keyword: "",
});

// 页数切换
const onChangePage = (page: number, pageSize: number) => {
  setListParams((draft) => {
    draft.page_num = page;
    draft.page_size = pageSize;
  });
};

// 获取列表
const { data: chunklist, refetch: listRefetch } = useQuery({
  queryKey: ["chunklist", listParams],
  queryFn: () => apiChunkList(listParams),
});
💡 queryKey 里带上 listParams,参数一变 key 就变,react-query 自动重新请求——这就是"条件变更主动触发",省掉一堆 useEffect。

4useMutation

useMutation 主要用于主动触发,如新增,删除,编辑等。

场景:新增表单

新增一个表单,点击确认保存,调用保存接口并刷新列表。apiApplicationAdd 为请求封装,addAppmutate 去了一个别名而已,后面可以调用这个 isPending 为请求状态。addAppmutate(values) 传递的参数,会传递给 apiApplicationAdd,onSuccess 回调成功刷新列表。

const { mutate: addAppmutate, isPending } = useMutation({
  mutationFn: apiApplicationAdd,
  onSuccess: () => {
    reload();
  },
});

// 新增应用
const handelAdd = async (values: any) => {
  addAppmutate(values);
};
📌 小结:useQuery 管"读"(查询+缓存+刷新),useMutation 管"写"(新增/删除/编辑),onSuccess 里 refetch 一下就是经典闭环。