useRequest-螞蟻中臺標準請求 Hooks

useRequst 文檔: https://hooks.umijs.org/zh-CN...

Umi Hooks Github 地址:https://github.com/umijs/hooksjavascript

useRequest 是一個超級強大,且生產完備的網絡請求 Hooks,目前已經成爲螞蟻中臺最佳實踐內置網絡請求方案。在螞蟻內部中臺應用,寫網絡請求,都推薦用 useRequest。前端

useRequest 多是目前社區中最強大,最接地氣的請求類 Hooks 了。能夠覆蓋 99% 的網絡請求場景,不管是讀仍是寫,不管是普通請求仍是分頁請求,不管是緩存仍是防抖節流,統統都能支持。只有你想不到,沒有它作不到(吹牛🐂~)。java

爲何要作 useRequest?

在組件開發中,要實現一個健壯的網絡請求,並非一個簡單的事情。正如我上一篇文章《Umi Hooks - 助力擁抱 React Hooks》舉的例子,實現一個網絡請求,咱們須要考慮 loading、競態處理、組件卸載等等方面。ios

固然經過 React Hooks 的邏輯封裝能力,咱們能夠將網絡請求相關的邏輯封裝起來。Umi Hooks 中的 useAsync 就作了這個事情,一行代碼就能夠實現網絡請求,提效很是明顯。git

但平常工做中,只用一個 useAsync 仍是不夠的,Umi Hooks 中和網絡請求相關的 Hooks 就有很是多。好比和分頁請求相關的 usePagination,請求自帶防抖的 useSearch,內置 umi-request 的 useAPI,加載更多場景的 useLoadMore,等等等等。github

目前已有 Hooks 有幾個很明顯的缺點:面試

  • 上手成本偏高,須要針對不一樣場景選擇不一樣的 Hooks。
  • 全部網絡請求 Hooks API,底層能力不一致。好比 usePagination 不支持手動觸發、不支持輪詢等等。
  • useAsync 能力不足,不少場景沒法知足需求,好比並行請求。

同時隨着 zeit/swr 的誕生,給了咱們不少靈感,原來網絡請求還能夠這麼玩!swr 有很是多好用,而且咱們想不到的能力。好比:axios

這裏我簡單科普下 swr。swr 是 stale-while-revalidate 的簡稱,最主要的能力是:咱們在發起網絡請求時,會優先返回以前緩存的數據,而後在背後發起新的網絡請求,最終用新的請求結果從新觸發組件渲染。swr 特性在特定場景,對用戶很是友好。

基於上面兩點,通過內部屢次討論,最終決定,咱們要作一個能力強大,覆蓋全部場景的網絡請求 Hooks!useRequest 誕生了!它不只囊括了當前 Umi Hooks 中全部和網絡請求相關的 Hooks 的能力,也大量借鑑了 swr 的優秀特性,香的不得了。c#

能力介紹

基礎網絡請求

import { useRequest } from '@umijs/hooks';

function getUsername() {
  return Promise.resolve('jack');
}

export default () => {
  const { data, error, loading } = useRequest(getUsername)
  
  if (error) return <div>failed to load</div>
  if (loading) return <div>loading...</div>
  return <div>Username: {data}</div>
}

這是一個最簡單的網絡請求示例。在這個例子中 useRequest 接收了一個 Promise 函數。在組件初始化時,會自動觸發 getUsername 執行,並自動管理 dataloadingerror 等數據,咱們只須要根據狀態來寫相應的 UI 實現便可。api

在線 demo

手動請求

對於「寫」請求,咱們通常須要手動觸發,好比添加用戶,編輯信息,刪除用戶等等。 useRequest 只須要配置 manual = true ,便可阻止初始化執行。只有觸發 run 時纔會開始執行。

2020-02-13 20.43.15.gif

import { useRequest } from '@umijs/hooks';

export default () => {
  const { run, loading } = useRequest(changeUsername, {manual: true})
  
  return (
    <Button onClick={() => run('new name')} loading={loading}>
       Edit
    </Button>
    )
}

在線 demo

輪詢

對於須要保持新鮮度的數據,咱們一般須要不斷髮起網絡請求以更新數據。 useRequest 只要配置 poilingInterval 便可自動定時發起網絡請求。

import { useRequest } from '@umijs/hooks';

export default () => {
  const { data } = useRequest(getUsername, { pollingInterval: 1000 })

  return <div>Username: {data}</div>
}

同時經過設置 pollingWhenHidden ,咱們能夠智能的實如今屏幕隱藏時,暫停輪詢。等屏幕恢復可見時,繼續請求,以節省資源。

固然你也能夠經過 run/cancel 來手動控制定時器的開啓和關閉。

在線 demo

並行請求

什麼是並行請求?看了下圖應該就明白了,也就是同一個接口,咱們須要維護多個請求狀態。

示例中的並行請求有幾個特色:

  • 刪除 n 個不一樣的用戶,則須要維護 n 個請求狀態。
  • 屢次刪除同一個用戶,則只須要維護最後一個請求。

2020-02-13 21.03.55.gif

useRequest 經過設置 fetchKey ,便可對請求進行分類。相同分類的請求,只會維護一份狀態。不一樣分類的請求,則會維護多份狀態。在下面的代碼中,咱們經過 userId 將請求進行分類,同時咱們能夠經過 fetches[userId] 拿到當前分類的請求狀態!

export default () => {
  const { run, fetches } = useRequest(deleteUser, {
    manual: true,
    fetchKey: id => id, // 不一樣的 ID,分類不一樣
  });

  return (
    <div>
      <Button loading={fetches.A?.loading} onClick={() => { run('A') }}>刪除 1</Button>
      <Button loading={fetches.B?.loading} onClick={() => { run('B') }}>刪除 2</Button>
      <Button loading={fetches.C?.loading} onClick={() => { run('C') }}>刪除 3</Button>
    </div>
  );
};

在線 demo

防抖 & 節流

一般在邊輸入邊搜索的場景中,咱們會用到防抖功能,以節省沒必要要的網絡請求。經過 useRequest ,只須要配置一個 debounceInterval ,就能夠很是簡單的實現對網絡請求的節流操做。

2020-02-13 21.24.40.gif

在下面的例子中,不管調用了多少次 run ,只會在輸入中止後,發送一次請求。

import { useRequest } from '@umijs/hooks';

export default () => {
  const { data, loading, run, cancel } = useRequest(getEmail, {
    debounceInterval: 500,
    manual: true
  });

  return (
    <div>
      <Select onSearch={run} loading={loading}>
        {data && data.map(i => <Option key={i} value={i}>{i}</Option>)}
      </Select>
    </div>
  );
};

節流與防抖是一樣的道理,只須要配置了 throttleInterval ,便可實現節流功能。

在線 demo

緩存 & SWR & 預加載

在前面我講了什麼是 SWR,在 SWR 場景下,咱們會對接口數據進行緩存,當下次請求該接口時,咱們會先返回緩存的數據,同時,在背後發起新的網絡請求,待新數據拿到後,從新觸發渲染。

對於一些數據不是常常變化的接口,使用 SWR 後,能夠極大提升用戶使用體驗。好比下面的圖片例子,當咱們第二次訪問該文章時,直接返回了緩存的數據,沒有任何的等待時間。同時,咱們能夠看到「最新訪問時間」在 2 秒後更新了,這意味着新的請求數據返回了。

2020-02-13 21.58.31.gif

useRequest 經過配置 cacheKey ,便可進入 SWR 模式,至關簡單。

const { data, loading } = useRequest(getArticle, {
    cacheKey: 'articleKey',
  });

同時須要注意,同一個 cacheyKey 的數據是全局共享的。經過這個特性,咱們能夠實現「預加載」功能。好比鼠標 hover 到文章標題時,咱們即發送讀取文章詳情的請求,這樣等用戶真正點進文章時,數據早已經緩存好了。

在線 demo

屏幕聚焦從新請求

經過配置 refreshOnWindowFocus ,咱們能夠實現,在屏幕從新聚焦或可見時,從新發起網絡請求。這個特性有什麼用呢?它能夠保證多個 tab 間數據的同步性。也能夠解決長間隔以後從新打開網站的數據新鮮度問題。

這裏借用 swr 的一個圖來講明問題。

2020-02-13 22.12.25.gif

在線 demo

集成請求庫

考慮到使用便捷性, useRequest 集成了 umi-request。若是第一個參數不是 Promise,咱們會經過 umi-request 來發起網絡請求。

固然若是你想用 axios,也是能夠的,經過 requstMethod 便可定製你本身的請求方法。

// 用法 1
const { data, error, loading } = useRequest('/api/userInfo');

// 用法 2
const { data, error, loading } = useRequest({
  url: '/api/changeUsername',
  method: 'post',
});

// 用法 3
const { data, error, loading } = useRequest((userId)=> `/api/userInfo/${userId}`);

// 用法 4
const { loading, run } = useRequest((username) => ({
  url: '/api/changeUsername',
  method: 'post',
  data: { username },
}));

在線 demo

分頁

中臺應用中最多的就是表格和表單了。對於一個表格,咱們要處理很是多的請求邏輯,包括不限於:

  • page、pageSize、total 管理
  • 篩選條件變化,重置分頁,從新發起網絡請求

useRequest 經過配置 paginated = true ,便可進入分頁模式,自動幫你處理表格常見邏輯,同時咱們對 antd Table 作了特殊支持,只用簡單幾行代碼,就能夠實現下面圖中這樣複雜的邏輯,提效百倍。

2020-02-13 22.34.40.gif

import {useRequest} from '@umijs/hooks';

export default () => {
  const [gender, setGender] = useState('male');
  const { tableProps } = useRequest((params)=>{
    return getTableData({...params, gender})
  }, {
    paginated: true,
    refreshDeps: [gender]
  });

  const columns = [];

  return (
    <Table columns={columns} rowKey="email" {...tableProps}/>
  );
};

在線 demo

加載更多

加載更多的場景也是平常開發中常見的需求。在加載場景中,咱們通常須要處理:

  • 分頁 offset、pageSize 等管理
  • 首次加載,加載更多狀態管理
  • 上拉自動加載更多
  • 組件第二次加載時,但願能記錄以前的數據,並滾動到以前的位置

    useRequest 經過設置 loadMore = true ,便可進入加載更多模式,配合其它參數,能夠幫你處理上面全部的邏輯。

2020-02-13 22.46.16.gif

const { data, loading, loadMore, loadingMore } = useRequest((d) => getLoadMoreList(d?.nextId, 3), {
  loadMore: true,
  cacheKey: 'loadMoreDemoCacheId',
  fetchKey: d => `${d?.nextId}-`,
});

在線 demo

更多

固然我前面也說了, useReqeust 的功能只有你想不到,沒有它沒有的。哈哈哈~

除了上面的特性,咱們還有一些其它的能力,能夠在文檔中發現。好比 loadingDelay

loadingDelay

經過設置 loadingDelay ,延遲 loading 變爲 true 的時間,當請求很快響應時,能夠有效避免 loading 變化致使的抖動。

2020-02-13 22.49.43.gif

總結

雖然 useRequest 的功能不少,也避免不了有些你想用的特性它不支持。但不用擔憂,你能夠很方面的基於 useRequest 去擴展。咱們的分頁模式,及加載更多模式均是基於底層能力擴展實現的。你能夠參考它們的代碼,實現本身的特有能力。

經過 useRequest ,能夠解決平常 99% 的網絡請求需求。奧利給!奧利給!

招聘

最後打個招聘廣告,螞蟻金服體驗技術部招聘前端啦!要求 P6 及以上!有興趣的同窗能夠發簡歷到

brickspert.fjl@antfin.com

brickspert.fjl@antfin.com

brickspert.fjl@antfin.com

我會幫您跟進面試進度的,期待您的加入~

相關文章
相關標籤/搜索