<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          使用React Query做為axios請(qǐng)求庫的上層封裝

          共 7324字,需瀏覽 15分鐘

           ·

          2021-09-29 17:59

          前言

          在項(xiàng)目中,通常都需要跟服務(wù)端進(jìn)行異步的數(shù)據(jù)交互,基本都是用到axios這個(gè)庫來做請(qǐng)求,嗯,畢竟擁有80k star,明星項(xiàng)目

          接下來,我們來回顧下axios在項(xiàng)目中的使用

          以查詢用戶信息為例,我們會(huì)這樣封裝

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

          我們?cè)儆胔ooks再封裝下這個(gè)請(qǐng)求,包括loading等中間態(tài)的封裝,處理的優(yōu)雅一點(diǎn)

          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>

            )
          }

          可以看到,我們的項(xiàng)目中基本上是這樣封裝請(qǐng)求,我們不僅要請(qǐng)求數(shù)據(jù),還要處理相應(yīng)的loading,error這些中間態(tài),這類通用的中間狀態(tài)處理邏輯可能在不同組件中重復(fù)寫很多次。

          另外,現(xiàn)在的前端項(xiàng)目特別是單頁面應(yīng)用,會(huì)使用Flux、Redux、Mobox等狀態(tài)管理庫,會(huì)把組件間共享的數(shù)據(jù)都存放在狀態(tài)管理庫中,這些可以分為兩類,一類是用戶交互的中間狀態(tài),比如isLoading,isClose,modalVisible等等,另外一類就是服務(wù)端狀態(tài)(數(shù)據(jù))

          我們一般處理的方式都是無差別的存放在全局狀態(tài)管理上,狀態(tài)管理庫為了兼容異步請(qǐng)求,就有了redux-saga,redux-action這些異步解決方案

          其實(shí)對(duì)于redux等狀態(tài)管理庫,本身是沒有異步這個(gè)概念,只有mutation這種操作,為了支持異步,硬是強(qiáng)加了異步action這種操作,實(shí)際這些異步中間件就是在最后的請(qǐng)求回調(diào)透?jìng)髁薲ispatch,諸如這些情況,我們不僅將數(shù)據(jù)一鍋燉放在全局狀態(tài)管理上,寫法上也使得項(xiàng)目越來越臃腫了(以至于出現(xiàn)后面rematch、dva方案進(jìn)行簡(jiǎn)化),我們有沒有想過,服務(wù)端的狀態(tài)就不應(yīng)該放在全局狀態(tài)管理上,全局狀態(tài)管理應(yīng)該專門處理用戶交互的中間狀態(tài)

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

          React Query

          React Query 通常被描述為 React 缺少的數(shù)據(jù)獲取(data-fetching)庫,但是從更廣泛的角度來看,它使 React 程序中的獲取,緩存,同步和更新服務(wù)器狀態(tài)變得輕而易舉。

          解決了什么問題

          服務(wù)端狀態(tài)有以下特點(diǎn):

          1. 存儲(chǔ)在遠(yuǎn)端,本地?zé)o法直接控制

          2. 需要異步 API 來查詢和更新

          3. 可能在不知情的情況下,被另一個(gè)請(qǐng)求方更改了數(shù)據(jù),導(dǎo)致數(shù)據(jù)不同步

          現(xiàn)有的狀態(tài)管理庫(如 Mobx、Redux等)適用于管理客戶端狀態(tài),但它們并不關(guān)心客戶端是如何異步請(qǐng)求遠(yuǎn)端數(shù)據(jù)的,所以他們并不適合處理異步的、來自服務(wù)端的狀態(tài)。

          而 React Query 就是為了解決服務(wù)端狀態(tài)帶來的上述問題而出現(xiàn)的,除此之外它還帶來了以下特性:

          1. 更方便地控制緩存

          2. 把對(duì)于相同數(shù)據(jù)的多個(gè)請(qǐng)求簡(jiǎn)化成一個(gè)

          3. 在后臺(tái)更新過期數(shù)據(jù)

          4. 知道數(shù)據(jù)什么時(shí)候會(huì)「過期」

          5. 對(duì)于數(shù)據(jù)的變化盡可能快得做出響應(yīng)

          6. 分頁查詢和懶加載等請(qǐng)求性能優(yōu)化

          7. 管理服務(wù)器狀態(tài)的內(nèi)存和垃圾回收

          8. 通過結(jié)構(gòu)共享(structural sharing)來緩存查詢結(jié)果

          請(qǐng)求中間態(tài)處理

           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會(huì)自動(dòng)把這些isLoading,isError請(qǐng)求中間態(tài)處理好,我們不必寫重復(fù)邏輯,另外配合Suspense提對(duì)一點(diǎn)對(duì)于loading場(chǎng)景的處理,Suspense也支持的不錯(cuò),特別是局部Loading,簡(jiǎn)直Nice!

          ReactQuery 的狀態(tài)管理

          Fetch, cache and update data in your React and React Native applications all without touching any "global state".

          官網(wǎng)對(duì)于React Query的簡(jiǎn)述,注意global state,你會(huì)不解,為什么React Query明明是一個(gè)請(qǐng)求庫,跟數(shù)據(jù)狀態(tài)管理又有什么關(guān)系,甚至可以處做全局狀態(tài)管理

          那是因?yàn)镽eactQuery 會(huì)在全局維護(hù)一個(gè)服務(wù)端狀態(tài)樹,根據(jù) Query key 去查找狀態(tài)樹中是否有可用的數(shù)據(jù),如果有則直接返回,否則則會(huì)發(fā)起請(qǐng)求,并將請(qǐng)求結(jié)果以 Query key 為主鍵存儲(chǔ)到狀態(tài)樹中。

          ReactQuery 就將我們所有的服務(wù)端狀態(tài)維護(hù)在全局,并配合它的緩存策略來執(zhí)行數(shù)據(jù)的存儲(chǔ)和更新。借助于這樣的特性,我們就可以將所有跟服務(wù)端進(jìn)行交互的數(shù)據(jù)從類似于 Redux 這樣的狀態(tài)管理工具中剝離,而全部交給 ReactQuery 來管理。

          舉個(gè)例子:

          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>

            );
          }

          上述方式是可以實(shí)現(xiàn)React Query狀態(tài)管理,但是有性能問題,其實(shí)本質(zhì)還是利用Context透?jìng)?/code>,我們知道Context處理prop drilling問題,但是有性能問題,詳情可查看這篇文章 精讀《React — 5 Things That Might Surprise You》

          不過令人費(fèi)解的是官方強(qiáng)調(diào)ReactQuery 的狀態(tài)管理,但是在官網(wǎng)例子并沒有給出類似的例子,上述例子還是在官方的github倉庫翻到

          作者說會(huì)在一個(gè)講座分析,后面我再深入研究,先留個(gè)坑

          參考文獻(xiàn)

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

          • https://github.com/tannerlinsley/react-query/discussions/489

          • https://github.com/tannerlinsley/react-query/discussions/329

          • https://tkdodo.eu/blog/react-query-as-a-state-manager


          瀏覽 60
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  奇米伊人777 | 成人网站久久视频 | 国产东北女人在线视频 | 一级性爱日逼 | 日韩激情成人网 |