【ReactQuery】理解ReactQuery的中的状态

在项目中使用ReactQuery也有一段时间了,接下来我将会结合自己的使用来总结一下ReactQuery的知识,这是第一篇理解ReactQuery的状态是为了更好的理解ReactQuery的各种用法

什么是 ReactQuery?

在回答这个问题之前有必要先来了解客户端有哪些状态,在客户端中状态其实主要分为两种:一种是和用户相关的设置它们通常存储在客户端,称为客户端状态 ;另一种则是来自服务器的称为服务器状态

ReactQuery 之前我们大多情况下没有对这两者进行区分,都是将它们视为 React 中的状态进行渲染,如果需要复用服务器状态我们通常会将它们存储在全局状态管理库中手动进行管理。

ReactQuery 出来则改变了这一点,ReactQuery 专注于 服务器状态 的管理,提供了请求状态管理(loadingerrorsuccess)、缓存、重试、轮询、预加载、后台更新数据等一系列功能,极大的简化了和服务器交互的代码

正因为 ReactQuery 提供很多复杂的功能,必然需要一些状态才能描述查询的完整过程, 下面我们来认识一下 ReactQuery 中和查询相关的一些状态

loading&error&success

涉及到请求我们通常都会维护 isLoadingisError 等状态来在不同阶段渲染不同的内容,如下面这段代码:

js 复制代码
import React, { useEffect, useState } from "react";

function UserInfo() {
  const [isLoading, setIsLoading] = useState(false);
  const [isError, setIsError] = useState(false);
  const [userInfo, setUserInfo] = useState();
  const fetchUserInfo = () => {
    setIsLoading(true);
    setIsError(false);
    fetch("https://xxxx/user")
      .then((res) => {
        setUserInfo(res.data);
      })
      .catch((err) => {
        setIsError(true);
      })
      .finally(() => {
        setIsLoading(false);
      });
  };
  useEffect(() => {
    fetchUserInfo();
  }, []);

  return <div>{isLoading ? <p>Loading...</p> : <Info {...userInfo} />}</div>;
}

export default UserInfo;

ReactQuery 也不例外在 useQuery 中返回了 isLoadingisErrorisSuccessdata 等状态描述了请求的成功与否

js 复制代码
import React, { useEffect, useState } from "react";
import { useQuery } from "react-query";

function UserInfo({ id }) {
  const fetchUserInfo = () => {
    setIsLoading(true);
    setIsError(false);
    fetch(`https://xxxx/user/${id}`)
      .then((res) => {
        setUserInfo(res.data);
      })
      .catch((err) => {
        setIsError(true);
      })
      .finally(() => {
        setIsLoading(false);
      });
  };
  const {
    data: userInfo,
    isError,
    isLoading,
  } = useQuery({
    queryFn: fetchUserInfo,
  });
  return <div>{isLoading ? <p>Loading...</p> : <Info {...userInfo} />}</div>;
}

export default UserInfo;

isLoading 仅仅是在初始数据加载或者 useQuery 的 queryKey 发生变化重新查询时才会是 true

fetching&idle&paused

ReactQuery 通过 isLoadingisSuccessisError 对初始化请求进行描述,但是 ReactQuery 具备重试缓存后台更新数据等功能上面的三种状态就没办法充分描述了

因此 ReactQuery 还提供了 fetchStatus,这个 fetchStatus 有三个可能的值:

  • idle:空闲状态,此时不会发起请求(有可能是缓存仍生效不需要发起请求)
  • fetching: 数据正在==获取==中 (有可能是初次发起获取,也有可能是数据过期了在后台获取数据,总之对于一个查询来说只要数据在获取就是 fetching 状态)
  • paused:数据暂停获取(对于数据获取情况总是多变的有可能有某些异常原因导致请求没有正常发起,此时查询 query 的状态就会变成 paused;等到⌛️可以发起数据了 ReactQuery 会发起请求,状态会重新变成 fetching )\

stale&fresh

ReactQuery 最重要的能力莫过于对缓存 的管理,怎么知道数据是新鲜的还是过期了呢?ReactQuery 中是通过 stale(过期)、fresh(新鲜)来进行描述

在默认情况下 useQuery 在组件挂载完成✅初次获取数据时会立刻变成过期状态,如果你想改变这一点就需要用到 staleTime 它可以设置缓存过期的时间,当数据超过定义的缓存有效时间就被标记为过期 stale 的,下次查询的时候会触发数据的更新和获取

js 复制代码
const userInfoQuery = useQuery({
	queryKey: ["userInfo"],
	queryFn: () => fetchUserInfo(id),
	staleTime: 1000 * 5,
});

说到 staleTime 就不得不提一嘴 cacheTime,它们两有什么区别呢?

  • staleTime:定义的是缓存的过期时间,类似于浏览器的 max-age,缓存过期了 ReactQuery 会讲缓存标记为过期的
  • cacheTime:定义的是缓存的==存储==时间,当 cacheTime 过期了,缓存就会被 ReactQuery 清空

active&inactive

对于查询本身也有活跃的(active)、不活跃的(inactive),如何理解活跃与不活跃呢?

当组件被挂载,使用到的 useQuery 查询会变成活跃状态,当组件被卸载,这个组件使用到的 useQuery 查询会变成非活跃状态,为了更直观的感受下面有一个小例子:

可以看到当我们将组件进行隐藏后组件卸载,随即用户信息组件中的查询就变成了 inactive 非活跃状态了

什么时候会触发更新

有了对上面对 Query 的各种状态的基本了解之后我们就可以来看一下,什么时候会触发查询的数据更新

  • 默认 ReactQuery 会在网络重新连接时会触发过期 stale 状态的查询数据获取,可以通过 refetchOnReconnect 这个查询配置进行修改
  • 默认在浏览器窗口 Window Focus 时会触发对 stale 过期状态的查询的数据获取
  • 默认会在组件 Mount(挂载) 时,触发 stale 过期的查询的数据获取
  • 除了上面的 ReactQuery 帮我们触发数据获取,ReactQuery 也提供了 queryClient.refetchQueriesqueryClient.invalidateQueries 给我们去触发数据的获取
js 复制代码
export default function Detail() {
  // 注意这里拿到的id是string
  const [isShow, setIsShow] = useState(true);
  const queryClient = useQueryClient();

  const refetchQueries = () => {
    queryClient.refetchQueries({
      queryKey: ["userInfo"],
    });
  };

  const invalidateQueries = () => {
    queryClient.invalidateQueries({
      queryKey: ["userInfo"],
    });
  };

  return (
    <div>
      <button onClick={() => setIsShow((isShow) => !isShow)}>
        {isShow ? "隐藏用户信息" : "展示用户信息"}
      </button>
      {isShow ? <UserInfo /> : null}
      <button onClick={refetchQueries}>refetchQueries</button>
      <button onClick={invalidateQueries}>invalidateQueries</button>
    </div>
  );
}

[!tip]

注意 queryClient.invalidateQueries 只会触发 active 活跃状态的查询,而 queryClient.refetchQueries 无论查询是否处于活跃状态都会触发数据重新获取

DEMO 地址:codesandbox.io/p/sandbox/r...

参考资料:ReactQuery官方文档📄 tanstack.com

相关推荐
J不A秃V头A22 分钟前
Vue3:编写一个插件(进阶)
前端·vue.js
司篂篂1 小时前
axios二次封装
前端·javascript·vue.js
姚*鸿的博客1 小时前
pinia在vue3中的使用
前端·javascript·vue.js
宇文仲竹2 小时前
edge 插件 iframe 读取
前端·edge
Kika写代码2 小时前
【基于轻量型架构的WEB开发】【章节作业】
前端·oracle·架构
天下无贼!3 小时前
2024年最新版Vue3学习笔记
前端·vue.js·笔记·学习·vue
Jiaberrr3 小时前
JS实现树形结构数据中特定节点及其子节点显示属性设置的技巧(可用于树形节点过滤筛选)
前端·javascript·tree·树形·过滤筛选
赵啸林3 小时前
npm发布插件超级简单版
前端·npm·node.js
罔闻_spider3 小时前
爬虫----webpack
前端·爬虫·webpack
吱吱鼠叔3 小时前
MATLAB数据文件读写:1.格式化读写文件
前端·数据库·matlab