欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

ahooks解決用戶多次提交方法示例

 更新時間:2022年07月11日 14:48:37   作者:Gopal  
這篇文章主要為大家介紹了ahooks解決用戶多次提交的方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

引言

本文是深入淺出 ahooks 源碼系列文章的第四篇,這個系列的目標(biāo)主要有以下幾點:

  • 加深對 React hooks 的理解。
  • 學(xué)習(xí)如何抽象自定義 hooks。構(gòu)建屬于自己的 React hooks 工具庫。
  • 培養(yǎng)閱讀學(xué)習(xí)源碼的習(xí)慣,工具庫是一個對源碼閱讀不錯的選擇。

注:本系列對 ahooks 的源碼解析是基于 v3.3.13。自己 folk 了一份源碼,主要是對源碼做了一些解讀,可見 詳情。

系列文章:

本文來探索一下 ahooks 的 useLockFn。

場景

試想一下,有這么一個場景,有一個表單,你可能多次提交,就很可能導(dǎo)致結(jié)果不正確。

解決這類問題的方法有很多,比如添加 loading,在第一次點擊之后就無法再次點擊。另外一種方法就是給請求異步函數(shù)添加上一個靜態(tài)鎖,防止并發(fā)產(chǎn)生。這就是 ahooks 的 useLockFn 做的事情。

useLockFn

useLockFn 用于給一個異步函數(shù)增加競態(tài)鎖,防止并發(fā)執(zhí)行。

它的源碼比較簡單,如下所示:

import { useRef, useCallback } from 'react';
// 用于給一個異步函數(shù)增加競態(tài)鎖,防止并發(fā)執(zhí)行。
function useLockFn<P extends any[] = any[], V extends any = any>(fn: (...args: P) => Promise<V>) {
  // 是否現(xiàn)在處于一個鎖中
  const lockRef = useRef(false);
  // 返回的是增加了競態(tài)鎖的函數(shù)
  return useCallback(
    async (...args: P) => {
      // 判斷請求是否正在進(jìn)行
      if (lockRef.current) return;
      // 請求中
      lockRef.current = true;
      try {
        // 執(zhí)行原有請求
        const ret = await fn(...args);
        // 請求完成,狀態(tài)鎖設(shè)置為 false
        lockRef.current = false;
        return ret;
      } catch (e) {
        // 請求失敗,狀態(tài)鎖設(shè)置為 false
        lockRef.current = false;
        throw e;
      }
    },
    [fn],
  );
}
export default useLockFn;

可以看到,它的入?yún)⑹钱惒胶瘮?shù),返回的是一個增加了競態(tài)鎖的函數(shù)。通過 lockRef 做一個標(biāo)識位,初始化的時候它的值為 false。當(dāng)正在請求,則設(shè)置為 true,從而下次再調(diào)用這個函數(shù)的時候,就直接 return,不執(zhí)行原函數(shù),從而達(dá)到加鎖的目的。

缺點

雖然實用,但缺點很明顯,我需要給每一個需要添加競態(tài)鎖的請求異步函數(shù)都手動加一遍。那有沒有比較通用和方便的方法呢?

答案是可以通過 axios 自動取消重復(fù)請求。

axios 自動取消重復(fù)請求

axios 取消請求

對于原生的 XMLHttpRequest 對象發(fā)起的 HTTP 請求,可以調(diào)用 XMLHttpRequest 對象的 abort 方法。

那么我們項目中常用的 axios 呢?它其實底層也是用的 XMLHttpRequest 對象,它對外暴露取消請求的 API 是 CancelToken??梢允褂萌缦拢?/p>

const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.post('/user/12345', {
  name: 'gopal'
}, {
  cancelToken: source.token
})
source.cancel('Operation canceled by the user.'); // 取消請求,參數(shù)是可選的

另外一種使用的方法是調(diào)用 CancelToken 的構(gòu)造函數(shù)來創(chuàng)建 CancelToken,具體使用如下:

const CancelToken = axios.CancelToken;
let cancel;
axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    cancel = c;
  })
});
cancel(); // 取消請求

如何自動取消重復(fù)的請求

知道了如何取消請求,那怎么做到自動取消呢?答案是通過 axios 的攔截器。

  • 請求攔截器:該類攔截器的作用是在請求發(fā)送前統(tǒng)一執(zhí)行某些操作,比如在請求頭中添加 token 相關(guān)的字段。
  • 響應(yīng)攔截器:該類攔截器的作用是在接收到服務(wù)器響應(yīng)后統(tǒng)一執(zhí)行某些操作,比如發(fā)現(xiàn)響應(yīng)狀態(tài)碼為 401 時,自動跳轉(zhuǎn)到登錄頁。

具體的做法如下:

第一步,定義幾個重要的輔助函數(shù)。

  • generateReqKey:用于根據(jù)當(dāng)前請求的信息,生成請求 Key。只有 key 相同才會判定為是重復(fù)請求。這一點很重要,而且可能跟具體的業(yè)務(wù)場景有關(guān),比如有一種請求,輸入框模糊搜索,用戶高頻輸入關(guān)鍵字,一次性發(fā)出多個請求,可能先發(fā)出的請求,最后才響應(yīng),導(dǎo)致實際搜索結(jié)果與預(yù)期不符。這種其實就只需要根據(jù) URL 和請求方法判定其為重復(fù)請求,然后取消之前的請求就可以了。

這里我認(rèn)為,如果有需要的話,可以暴露一個 API 給開發(fā)者進(jìn)行自定義重復(fù)的規(guī)則。這里我們先根據(jù)請求方法、url、以及參數(shù)生成唯一的 key 去做。

function generateReqKey(config) {
  const { method, url, params, data } = config;
  return [method, url, Qs.stringify(params), Qs.stringify(data)].join("&");
}
  • addPendingRequest。用于把當(dāng)前請求信息添加到 pendingRequest 對象中。
const pendingRequest = new Map();
function addPendingRequest(config) {
  const requestKey = generateReqKey(config);
  config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => {
    if (!pendingRequest.has(requestKey)) {
       pendingRequest.set(requestKey, cancel);
    }
  });
}
  • removePendingRequest。檢查是否存在重復(fù)請求,若存在則取消已發(fā)的請求。
function removePendingRequest(config) {
  const requestKey = generateReqKey(config);
  if (pendingRequest.has(requestKey)) {
     const cancelToken = pendingRequest.get(requestKey);
     cancelToken(requestKey);
     pendingRequest.delete(requestKey);
  }
}

第二步,添加請求攔截器。

axios.interceptors.request.use(
  function (config) {
    removePendingRequest(config); // 檢查是否存在重復(fù)請求,若存在則取消已發(fā)的請求
    addPendingRequest(config); // 把當(dāng)前請求信息添加到pendingRequest對象中
    return config;
  },
  (error) => {
     return Promise.reject(error);
  }
);

第二步,添加響應(yīng)攔截器。

axios.interceptors.response.use(
  (response) => {
     removePendingRequest(response.config); // 從pendingRequest對象中移除請求
     return response;
   },
   (error) => {
      removePendingRequest(error.config || {}); // 從pendingRequest對象中移除請求
      if (axios.isCancel(error)) {
        console.log("已取消的重復(fù)請求:" + error.message);
      } else {
        // 添加異常處理
      }
      return Promise.reject(error);
   }
);

到這一步,我們就通過 axios 完成了自動取消重復(fù)請求的功能。

思考與總結(jié)

雖然可以通過類似 useLockFn 這樣的 hook或方法給請求函數(shù)添加競態(tài)鎖的方式解決重復(fù)請求的問題。但這種還是需要依賴于開發(fā)者的習(xí)慣,如果沒有一些規(guī)則的約束,很難避免問題。

通過 axios 攔截器以及其 CancelToken 功能,我們能夠在攔截器中自動將已發(fā)的請求取消,當(dāng)然假如有一些接口就是需要重復(fù)發(fā)送請求,可以考慮加一下白名單功能,讓請求不進(jìn)行取消。

參考 Axios 如何取消重復(fù)請求?

以上就是ahooks解決用戶多次提交方法示例的詳細(xì)內(nèi)容,更多關(guān)于ahooks用戶多次提交的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • React中如何引入Angular組件詳解

    React中如何引入Angular組件詳解

    這篇文章主要給大家介紹了關(guān)于React中如何引入Angular組件的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-08-08
  • react render的原理及觸發(fā)時機(jī)說明

    react render的原理及觸發(fā)時機(jī)說明

    這篇文章主要介紹了react render的原理及觸發(fā)時機(jī)說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • 一文詳解ReactNative狀態(tài)管理redux-toolkit使用

    一文詳解ReactNative狀態(tài)管理redux-toolkit使用

    這篇文章主要為大家介紹了ReactNative狀態(tài)管理redux-toolkit使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • React實現(xiàn)全局組件的Toast輕提示效果

    React實現(xiàn)全局組件的Toast輕提示效果

    這篇文章主要介紹了React實現(xiàn)全局組件的Toast輕提示效果,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-09-09
  • 詳解React中Props的淺對比

    詳解React中Props的淺對比

    這篇文章主要介紹了React中Props的淺對比的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用React,感興趣的朋友可以了解下
    2021-05-05
  • react?fiber使用的關(guān)鍵特性及執(zhí)行階段詳解

    react?fiber使用的關(guān)鍵特性及執(zhí)行階段詳解

    這篇文章主要為大家介紹了react?fiber使用的關(guān)鍵特性及執(zhí)行階段詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • 利用React實現(xiàn)虛擬列表的示例代碼

    利用React實現(xiàn)虛擬列表的示例代碼

    虛擬列表,其實就是將一個原本需要全部列表項的渲染的長列表,改為只渲染可視區(qū)域內(nèi)的列表項,但滾動效果還是要和渲染所有列表項的長列表一樣。本文就將利用React實現(xiàn)虛擬列表,需要的可以參考一下
    2022-08-08
  • 淺談React底層實現(xiàn)原理

    淺談React底層實現(xiàn)原理

    本文主要介紹了淺談React底層實現(xiàn)原理,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • React精髓!一篇全概括小結(jié)(急速)

    React精髓!一篇全概括小結(jié)(急速)

    這篇文章主要介紹了React精髓!一篇全概括小結(jié)(急速),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-05-05
  • React組件里this指向了undefined原理解析

    React組件里this指向了undefined原理解析

    這篇文章主要為大家介紹了React組件里this指向了undefined原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03

最新評論