请求数据管理

React中,我们可以直接使用XHRfetchaxios等进行AJAX请求。但在实际开发中,请求接口时经常有很多类似的功能需要重复编写,比如获取请求状态、分页加载、缓存等。react-query是一个目前比较流行的请求管理库,它封装了这些功能并和React Hooks能够良好的集成到一起,因此比较推荐使用。react-query的作者是美国程序员Tanner Linsley。

官方文档:https://tanstack.com/query/latest

Github地址:https://github.com/tanstack/query

安装React Query

react-query的最新版本是v4版本,我们执行以下命令安装:

npm install @tanstack/react-query --save

React Query基本使用

React Query提供了很多和异步请求有关的常用功能最佳实践,API也比繁杂。我们这里先不管那么多,先通过一个例子观察React Query如何配置使用,后面再讲解具体的参数和用法。下面例子中,我们使用React Query实现了一个最简单的Fetch请求管理。

index.js

import React from "react";
import ReactDOM from "react-dom/client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import StudentManage from "./StudentManage";

const queryClient = new QueryClient();

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <QueryClientProvider client={queryClient}>
      <StudentManage />
    </QueryClientProvider>
  </React.StrictMode>
);

StudentManage.jsx

import { useQuery } from "@tanstack/react-query";

const StudentManage = () => {
  const getStudentList = async () => {
    const rsp = await fetch("/api/getStudentList", {
      method: "GET",
    });
    return await rsp.json();
  };

  const { isLoading, data } = useQuery({
    queryKey: ["studentList"],
    queryFn: getStudentList,
    enabled: true,
  });

  return <div>{isLoading ? "Loading..." : JSON.stringify(data)}</div>;
};

export default StudentManage;

index.js中我们创建了QueryClient对象,并将其赋予<QueryClientProvider>组件,这些组件提供了处理请求和缓存的功能,我们将其在根组件上配置好,子组件便能使用Hooks函数操作相关的功能。

StudentManage.jsx中,getStudentList()是我们自定义的异步函数,它使用fetch()请求数据。我们使用了useQuery对这个请求函数再次进行了封装,useQuery提供了丰富的功能对请求进行管理,我们这里使用的isLoading属性就能够方便的读取请求状态,配置为enabled: true它便可以在页面加载后自动执行(enabled默认值为true,因此实际开发中如果需要请求自动执行不需要显示的写出,这里仅作为示例)。

JSX中,页面刷新后请求会自动执行,我们在请求过程中显示“Loading...”字样,请求完成后显示接口返回的数据。

useQuery配置

useQuery的参数是一个对象,其中指定了请求的配置信息。

useQuery(queryKey, queryFn, otherOptions)

下面我们详细介绍useQuery的使用方法。

queryKey

queryKey是对应一个请求的唯一标识,React Query通过这个唯一标识判断哪个请求需要更新。queryKey是一个数组,它可以接收多个参数,一般我们会在第1个参数中传递请求名字(字符串),后面跟着请求的参数。

const { isLoading, data } = useQuery({
  queryKey: ["studentList", classId],
  queryFn: async ({ queryKey }) => {
    const rsp = await fetch("/api/getStudentList?classId=" + queryKey[1], {
      method: "GET",
    });
    return await rsp.json();
  },
  enabled: true,
});

上面例子中,我们的queryKey第2个参数值就是请求的GET参数,它也会传递到queryFn中。当queryKey中的请求参数发生变化时,请求会被重新触发(这类似于useEffect的设计)。

queryFn

queryFn属性需要设置为一个异步函数,其内部逻辑就是调用接口,我们可以自己选用axios、Fetch等方式请求接口,异步函数的返回值会被放入useQuery返回值的data属性中。

实际使用中,还会涉及到向接口传递参数问题。前面介绍过请求参数我们可以将其放在queryKey中,useQuery会将QueryFunctionContext参数传递给queryFn,我们可以在queryFn中通过QueryFunctionContext解构获取queryKey

queryFn: async ({ queryKey }) => {};

获取请求返回数据

前面例子中我们已经演示如何获取请求返回的数据了,我们直接从useQuery的返回值中解构data属性即可。

const { isLoading, data } = useQuery({
  queryKey: ["studentList"],
  queryFn: getStudentList,
});

useQuery内部使用了useState来追踪组件的状态,并在数据改变时触发组件函数的重新执行。

获取请求状态

React Query的请求状态分为statusfetchStatus两部分,它们都可以通过useQuery的返回值解构获得。

status取值:

  • loading:加载中
  • error:失败
  • success:成功

fetchStatus取值:

  • paused:请求暂停
  • idle:空闲
  • fetching:正在请求

这些状态值都有对应的is属性供我们直接判断,比如isLoadingisError等。之前的例子代码中,我们就通过isLoading对当前状态是否为请求中进行了判断。在请求完成之前,data的值都是undefined

注意:状态判断这里有一点比较坑,对于页面加载后自动开始的请求可以用if (isLoading) {},对于手动触发的请求我们则需要用if (isLoading && isFetching) {},因为非自动的请求isLoading在请求触发前一直都是true

实现依赖请求

如果存在多个useQuery函数,它们会并发执行。但实际开发中,我们可能遇到需要依赖请求的情况,比如先调用funcA获取数据,再调用funcB获取数据,没有前一步的返回数据后一步是无法执行的。React Query中我们可以通过设置enabled属性来实现依赖请求。

const { data: dataA } = useQuery({
  queryKey: ["funcA"],
  queryFn: funcA,
});

const { data: dataB } = useQuery({
  queryKey: ["funcB"],
  queryFn: funcB,
  enabled: !!dataA,
});

上面例子中,在获取到dataA数据之前,其值为undefined,因此funcBenabled属性为falsefuncA执行完成dataAuseQuery内部被赋值,同时触发组件函数的重新执行,此时dataA有数据因此funcBenabled属性变为truefuncB执行。

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。
Copyright © 2017-2024 Gacfox All Rights Reserved.
Build with NextJS | Sitemap