最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 基于 ReactQuery 的服务端状态管理

    正文概述 掘金(Chaaaaaaarles)   2021-01-28   502

    背景

    在项目中,通常都需要跟服务端进行异步的数据交互,这包括 查询变更。 以一个简单的列表查询为例,我们通过 axios 去请求服务端的列表数据: 基于 ReactQuery 的服务端状态管理

    OK! 数据已经成功的取到了,也就是我们完成了跟服务端的一次查询交互了。现在我们来尝试更进一步,在 React 中可以通过实现一个 Hooks 把查询做的更优雅一点: 基于 ReactQuery 的服务端状态管理

    Perfect!? 并没有!

    我们遗漏了非常重要的 请求状态 的处理,包括异常和请求进行中的情况,让我们继续完善 useListQuery: 基于 ReactQuery 的服务端状态管理

    以上,就是一个典型的请求处理的场景,为了实现它,我们写了近 30 行代码 ... 用来刷代码行数也是极其不错的 ... ?

    那难道没有一种标准的请求处理模式吗?当然有!接下来我们进入正题,来看看 ReactQuery 的解决方案。

    请求处理模式

    初识 ReactQuery 的第一印象,通常都源于它提供的开箱即用的 QueryMutation 的 API.

    这就是 ReactQuery 能力的第一重境界 -- 请求处理

    它通过 useQueryuseMutation 等 Hooks API, 提供了一系列标准的请求处理模式。

    查询

    那么首先来看看 ReactQuery 是怎么处理我们的列表请求的: 基于 ReactQuery 的服务端状态管理

    useQuery 通常包含两个参数:

    1. 一个能唯一标识这个请求的 Query key
    2. 一个真正执行请求并返回数据的异步方法

    ReactQuery 的缓存策略是基于这个 key 来实现的。key 值除了字符串外,还可以是一个数组或者对象:

    useQuery('list', ...)
    useQuery(['list'], ...)
    
    // 数组或对象作为 key 时通常都包含查询条件
    useQuery(['list', 1], ...)
    userQuery(['list', {
      page: 1
    }])
    useQuery({
      type: 'list',
      page: 1
    })
    

    Query key 唯一的要求就是可以被序列化

    而对于请求方法,useQuery 要求是一个 then-able 的函数即可,在我们日常使用情况中,通常指代的就是返回 Promise, 而 Promise 的返回值即请求的响应数据。

    变更

    useQuery 类似,ReactQuery 也提供了数据变更的 Hooks API: 基于 ReactQuery 的服务端状态管理

    useMutation 的参数通常包含一个真正执行请求的异步方法,返回值第一项为逻辑完备的 mutate 异步方法,在按钮点击后,可以通过调用 mutate 提交数据以及状态的处理。

    ReactQuery 在请求处理上给我们提供了一个标准的处理方案,但是它的角色远不止请求库这么简单。在官方文档的 Overview 中作者就给了一个定位:

    全局服务端状态管理

    接下来,进入 ReactQuery 的第二重境界 -- 全局服务端状态管理

    Global Server State Management

    什么是 Server State

    首先,我们需要知道什么是服务端状态。在无意识的行为中,我们通常都将所有的组件渲染所需要的数据都放在一起管理,比如放在 State 中或者通过 Redux 这类状态管理库来管理。

    然而,我们再来斟酌一下我们的数据,是不是通常都有明显的来源特征:

    • 列表数据、详情数据等通过调接口由服务端提供的数据;
    • 选中状态、折叠状态这类由客户端来维护的状态;

    基于数据的来源,我们就可以将组件渲染所需要的状态分为服务端状态客户端状态

    ReactQuery 的状态管理

    ReactQuery 就将我们所有的服务端状态维护在全局,并配合它的缓存策略来执行数据的存储和更新。借助于这样的特性,我们就可以将所有跟服务端进行交互的数据从类似于 Redux 这样的状态管理工具中剥离,而全部交给 ReactQuery 来管理。

    ReactQuery 会在全局维护一个服务端状态树,根据 Query key 去查找状态树中是否有可用的数据,如果有则直接返回,否则则会发起请求,并将请求结果以 Query key 为主键存储到状态树中。

    缓存

    ReactQuery 的缓存策略使用了 stale-while-revalidate. 在 MDN 的 Cache Control 中对这个缓存策略的解释是:

    在 ReactQuery 中的体现是,可以接受状态树中存储的 stale 状态数据, 并且会在缓存失效新的查询实例被构建refetch 等行为后执行更新状态。

    关于 ReactQuery 缓存的处理过程,官方给了一个详细的示例

    ReactQuery 还能解决这些问题

    刷新列表状态

    日常开发工作中经常需要处理在添加、删除或者编辑后刷新列表的数据。为了实现这个行为,我们通常需要将列表数据的状态抽取到列表和详情的父组件中去管理: 基于 ReactQuery 的服务端状态管理

    然而,在模式上,列表数据的只是 List 组件的数据源,应该收敛到 List 组件中去管理,而不应该放在父组件中。那如果这样的话,兄弟组件之间如何通信以达到更新列表数据的目的?似乎问题变得越来越复杂 ...

    不怕!ReactQuery 来帮我们解这个问题~ 前面我们说过 ReactQuery 维护的是一个全局的状态树,那既然是全局的,问题不就简单了:

    基于 ReactQuery 的服务端状态管理

    ReactQuery 提供了 queryCache.invalidateQueries 可以直接指定某个 Query key 的缓存数据失效,这样 ReactQuery 就会在后台自动重新拉取最新的数据并更新到状态树中,这样列表组件中就渲染最新的数据了!完美!

    usePaginatedQuery 和 useInfiniteQuery

    除了基础的 useQuery 外,ReactQuery 还提供了 usePaginatedQueryuseInfiniteQuery, 分别来处理 分页无限加载 两个细分场景下的查询。

    通过上述 API, 可以让我们在代码中免去维护类似于 分页 这样的客户端状态。

    const [pagination, setPagination] = React.useState({
      currentPage: 1,
      pageSize: 10,
      totalSize: 0
    });
    

    更多

    除了本文中提到的这些基础能力外,ReactQuery 还提供了 PrefetchingSSROptimistic Updates 等高级特性。

    另外,除了我们上面用到的 queryCache.invalidateQueries , queryCache 还包含很多 API 来方便我们做一些手动的的状态操作。

    重要提示

    • 如果您看了本篇文章并开始使用 ReactQuery了,请一定不要忽视官方文档中的 Guides & Concepts: Important Defaults 中的 Important Defaults, 了解 ReactQuery 有那些默认的行为设置,这会帮助您构建更健壮的应用。
    • 本文编写时基于 ReactQuery@2 版本,目前 ReactQuery@3 版本已发布

    我们是阿里巴巴 CCO 技术部团队,希望有更多的同学加入跟我们一起做更多有意义的事情。技术栈限 React,有 Typescript 经验者更佳,Base 南京或杭州。有意者联系:henry.lx@alibaba-inc.com


    起源地下载网 » 基于 ReactQuery 的服务端状态管理

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元