最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 使用React Query作为axios请求库的上层封装 - 掘金

    正文概述 掘金(落落落洛克)   2021-09-16   659

    前言

    在项目中,通常都需要跟服务端进行异步的数据交互,基本都是用到axios这个库来做请求,嗯,毕竟拥有80k star,明星项目

    接下来,我们来回顾下axios在项目中的使用

    以查询用户信息为例,我们会这样封装

    async function requestUsers(){
      const {data} =await axios.get('/api/users');
      return data;
    }
    

    我们再用hooks再封装下这个请求,包括loading等中间态的封装,处理的优雅一点

    import React, {useState,useEffect} from 'react';
    import axios from 'axios';
    function useUsersQuery(){
      const [data,setData] = useState([]);
      const [isLoading,setLoading] = useState(false);
      const [isError,setError] = useState(false)
      useEffect(()=>{
        (async()=>{
           setLoading(true);
           try{
              const {data} = await axios.get('/api/users');
              setData(data);
           } catch((()=>{
              setError(true);
           })
           setLoading(false);
        })()
      })
      return { 
         data,
         isLoading,
         isError
      };
    }
    function UserList(){
      const {data, isLoading,isError} = useUsersQuery();
      if (isLoading) {
            return <div>loading</div>;
       }
      if (isError) {
            return <div>error</div>;
       }
      return (
        <div>
           {
             data.map((item)=>{
                return <div>{item.name}</div>
             })
           }
        </div>
      )
    }
    

    可以看到,我们的项目中基本上是这样封装请求,我们不仅要请求数据,还要处理相应的loading,error这些中间态,这类通用的中间状态处理逻辑可能在不同组件中重复写很多次。

    另外,现在的前端项目特别是单页面应用,会使用Flux、Redux、Mobox等状态管理库,会把组件间共享的数据都存放在状态管理库中,这些可以分为两类,一类是用户交互的中间状态,比如isLoading,isClose,modalVisible等等,另外一类就是服务端状态(数据)

    我们一般处理的方式都是无差别的存放在全局状态管理上,状态管理库为了兼容异步请求,就有了redux-saga,redux-action这些异步解决方案

    其实对于redux等状态管理库,本身是没有异步这个概念,只有mutation这种操作,为了支持异步,硬是强加了异步action这种操作,实际这些异步中间件就是在最后的请求回调透传了dispatch,诸如这些情况,我们不仅将数据一锅炖放在全局状态管理上,写法上也使得项目越来越臃肿了(以至于出现后面rematch、dva方案进行简化),我们有没有想过,服务端的状态就不应该放在全局状态管理上,全局状态管理应该专门处理用户交互的中间状态

    使用React Query作为axios请求库的上层封装 - 掘金

    接下来,就是引出今天的主角 React Query

    React Query

    解决了什么问题

    服务端状态有以下特点:

    1. 存储在远端,本地无法直接控制

    2. 需要异步 API 来查询和更新

    3. 可能在不知情的情况下,被另一个请求方更改了数据,导致数据不同步

    现有的状态管理库(如 Mobx、Redux等)适用于管理客户端状态,但它们并不关心客户端是如何异步请求远端数据的,所以他们并不适合处理异步的、来自服务端的状态。

    而 React Query 就是为了解决服务端状态带来的上述问题而出现的,除此之外它还带来了以下特性:

    1. 更方便地控制缓存

    2. 把对于相同数据的多个请求简化成一个

    3. 在后台更新过期数据

    4. 知道数据什么时候会「过期」

    5. 对于数据的变化尽可能快得做出响应

    6. 分页查询和懒加载等请求性能优化

    7. 管理服务器状态的内存和垃圾回收

    8. 通过结构共享(structural sharing)来缓存查询结果

    请求中间态处理

     function Todos() {
       const { isLoading, isError, data, error } = useQuery('todos', fetchTodoList)
    
       if (isLoading) {
         return <span>Loading...</span>
       }
    
       if (isError) {
         return <span>Error: {error.message}</span>
       }
    
       // also status === 'success', but "else" logic works, too
       return (
         <ul>
           {data.map(todo => (
             <li key={todo.id}>{todo.title}</li>
           ))}
         </ul>
       )
     }
    

    React query会自动把这些isLoading,isError请求中间态处理好,我们不必写重复逻辑,另外提多一点,对于loading场景的处理,Suspense也支持的不错,特别是局部Loading,简直Nice!

    ReactQuery 的状态管理

    官网对于React Query的简述,注意global state,你会不解,为什么React Query明明是一个请求库,跟数据状态管理又有什么关系,甚至可以处做全局状态管理

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

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

    举个例子:

    import React from "react";
    import { useQuery, queryCache } from "react-query";
    import "./styles.css";
    
    export default function App() {
      return (
        <div className="App">
          <h1>Shared state using react-query</h1>
          <Comp1 />
          <Comp2 />
        </div>
      );
    }
    
    function useSharedState(key, initialValue) {
      const { data: state } = useQuery(key, () => queryCache.getQueryData(key), {
        initialData: initialValue
      });
    
      const setState = value => queryCache.setQueryData(key, value);
    
      return [state, setState];
    }
    
    function Comp1() {
      const [count, setCount] = useSharedState("count", 1);
    
      console.log("comp1 rendered");
    
      return (
        <div>
          <p>Count: {count}</p>
          <button onClick={() => setCount(count + 1)}>add</button>
        </div>
      );
    }
    
    function Comp2() {
      const [count, setCount] = useSharedState("count", 2);
    
      console.log("comp2 rendered");
    
      return (
        <div>
          <p>Count: {count}</p>
          <button onClick={() => setCount(count + 1)}>add</button>
        </div>
      );
    }
    

    上述方式是可以实现React Query状态管理,但是有性能问题,其实本质还是利用Context透传,我们知道Context处理prop drilling问题,但是有性能问题,详情可查看这篇文章 精读《React — 5 Things That Might Surprise You》

    不过令人费解的是官方强调ReactQuery 的状态管理,但是在官网例子并没有给出类似的例子,上述例子还是在官方的github仓库翻到

    使用React Query作为axios请求库的上层封装 - 掘金

    作者说会在一个讲座分析,后面我再深入研究,先留个坑

    使用React Query作为axios请求库的上层封装 - 掘金

    参考文献

    • react-query.tanstack.com/quick-start

    • github.com/tannerlinsl…

    • github.com/tannerlinsl…

    • tkdodo.eu/blog/react-…


    起源地下载网 » 使用React Query作为axios请求库的上层封装 - 掘金

    常见问题FAQ

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

    发表评论

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

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

    联系作者

    请选择支付方式

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