我的编程空间,编程开发者的网络收藏夹
学习永远不晚

ahooks解决用户多次提交方法示例

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

ahooks解决用户多次提交方法示例

引言

本文是深入浅出 ahooks 源码系列文章的第四篇,这个系列的目标主要有以下几点:

  • 加深对 React hooks 的理解。
  • 学习如何抽象自定义 hooks。构建属于自己的 React hooks 工具库。
  • 培养阅读学习源码的习惯,工具库是一个对源码阅读不错的选择。

注:本系列对 ahooks 的源码解析是基于 v3.3.13。自己 folk 了一份源码,主要是对源码做了一些解读,可见 详情。

系列文章:

  • 大家都能看得懂的源码(一)ahooks 整体架构篇
  • 如何使用插件化机制优雅的封装你的请求hook
  • ahooks 是怎么解决 React 的闭包问题的?

本文来探索一下 ahooks 的 useLockFn。

场景

试想一下,有这么一个场景,有一个表单,你可能多次提交,就很可能导致结果不正确。

解决这类问题的方法有很多,比如添加 loading,在第一次点击之后就无法再次点击。另外一种方法就是给请求异步函数添加上一个静态锁,防止并发产生。这就是 ahooks 的 useLockFn 做的事情。

useLockFn

useLockFn 用于给一个异步函数增加竞态锁,防止并发执行。

它的源码比较简单,如下所示:

import { useRef, useCallback } from 'react';
// 用于给一个异步函数增加竞态锁,防止并发执行。
function useLockFn<P extends any[] = any[], V extends any = any>(fn: (...args: P) => Promise<V>) {
  // 是否现在处于一个锁中
  const lockRef = useRef(false);
  // 返回的是增加了竞态锁的函数
  return useCallback(
    async (...args: P) => {
      // 判断请求是否正在进行
      if (lockRef.current) return;
      // 请求中
      lockRef.current = true;
      try {
        // 执行原有请求
        const ret = await fn(...args);
        // 请求完成,状态锁设置为 false
        lockRef.current = false;
        return ret;
      } catch (e) {
        // 请求失败,状态锁设置为 false
        lockRef.current = false;
        throw e;
      }
    },
    [fn],
  );
}
export default useLockFn;

可以看到,它的入参是异步函数,返回的是一个增加了竞态锁的函数。通过 lockRef 做一个标识位,初始化的时候它的值为 false。当正在请求,则设置为 true,从而下次再调用这个函数的时候,就直接 return,不执行原函数,从而达到加锁的目的。

缺点

虽然实用,但缺点很明显,我需要给每一个需要添加竞态锁的请求异步函数都手动加一遍。那有没有比较通用和方便的方法呢?

答案是可以通过 axios 自动取消重复请求。

axios 自动取消重复请求

axios 取消请求

对于原生的 XMLHttpRequest 对象发起的 HTTP 请求,可以调用 XMLHttpRequest 对象的 abort 方法。

那么我们项目中常用的 axios 呢?它其实底层也是用的 XMLHttpRequest 对象,它对外暴露取消请求的 API 是 CancelToken。可以使用如下:

const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.post('/user/12345', {
  name: 'gopal'
}, {
  cancelToken: source.token
})
source.cancel('Operation canceled by the user.'); // 取消请求,参数是可选的

另外一种使用的方法是调用 CancelToken 的构造函数来创建 CancelToken,具体使用如下:

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

如何自动取消重复的请求

知道了如何取消请求,那怎么做到自动取消呢?答案是通过 axios 的拦截器。

  • 请求拦截器:该类拦截器的作用是在请求发送前统一执行某些操作,比如在请求头中添加 token 相关的字段。
  • 响应拦截器:该类拦截器的作用是在接收到服务器响应后统一执行某些操作,比如发现响应状态码为 401 时,自动跳转到登录页。

具体的做法如下:

第一步,定义几个重要的辅助函数。

  • generateReqKey:用于根据当前请求的信息,生成请求 Key。只有 key 相同才会判定为是重复请求。这一点很重要,而且可能跟具体的业务场景有关,比如有一种请求,输入框模糊搜索,用户高频输入关键字,一次性发出多个请求,可能先发出的请求,最后才响应,导致实际搜索结果与预期不符。这种其实就只需要根据 URL 和请求方法判定其为重复请求,然后取消之前的请求就可以了。

这里我认为,如果有需要的话,可以暴露一个 API 给开发者进行自定义重复的规则。这里我们先根据请求方法、url、以及参数生成唯一的 key 去做。

function generateReqKey(config) {
  const { method, url, params, data } = config;
  return [method, url, Qs.stringify(params), Qs.stringify(data)].join("&");
}
  • addPendingRequest。用于把当前请求信息添加到 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。检查是否存在重复请求,若存在则取消已发的请求。
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); // 检查是否存在重复请求,若存在则取消已发的请求
    addPendingRequest(config); // 把当前请求信息添加到pendingRequest对象中
    return config;
  },
  (error) => {
     return Promise.reject(error);
  }
);

第二步,添加响应拦截器。

axios.interceptors.response.use(
  (response) => {
     removePendingRequest(response.config); // 从pendingRequest对象中移除请求
     return response;
   },
   (error) => {
      removePendingRequest(error.config || {}); // 从pendingRequest对象中移除请求
      if (axios.isCancel(error)) {
        console.log("已取消的重复请求:" + error.message);
      } else {
        // 添加异常处理
      }
      return Promise.reject(error);
   }
);

到这一步,我们就通过 axios 完成了自动取消重复请求的功能。

思考与总结

虽然可以通过类似 useLockFn 这样的 hook或方法给请求函数添加竞态锁的方式解决重复请求的问题。但这种还是需要依赖于开发者的习惯,如果没有一些规则的约束,很难避免问题。

通过 axios 拦截器以及其 CancelToken 功能,我们能够在拦截器中自动将已发的请求取消,当然假如有一些接口就是需要重复发送请求,可以考虑加一下白名单功能,让请求不进行取消。

参考 Axios 如何取消重复请求?

以上就是ahooks解决用户多次提交方法示例的详细内容,更多关于ahooks用户多次提交的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

ahooks解决用户多次提交方法示例

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

ahooks怎么解决用户多次提交问题

这篇文章主要介绍“ahooks怎么解决用户多次提交问题”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“ahooks怎么解决用户多次提交问题”文章能帮助大家解决问题。场景试想一下,有这么一个场景,有一个
2023-07-02

删除windows用户时提示 用户不属于此组 解决方法

问题:   近日我在公司的服务器里发现了这个用户帐户server$,估计的被人当成肉鸡了……   这个帐户不属于任何组,不属于GUESTS,也不属于ADMINISTRATORS,但权限是管理员的权限。   然后我
2023-05-25

dedecms提示你的用户名不存在的解决方法

数据库的admin表看看有没有这个用户名。没有的话就是真不存在了。编程客栈有的话可能是你的数据库连接有误。编程客栈看下data文件夹下面的common.inc.编程客栈php里面编程客栈的用户名密码有没有写错jfxIin。
2022-06-12

linux使用su切换用户时提示Authentication failure的解决方法

这篇文章主要讲解了“linux使用su切换用户时提示Authentication failure的解决方法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“linux使用su切换用户时提示Aut
2023-06-13

linux重置密码提示与用户名相似的解决方法

小编给大家分享一下linux重置密码提示与用户名相似的解决方法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!方法如下一、核实是否是密码复杂度问题1、使用命令:vi
2023-06-10

Win8提示“已禁用IME”的解决方法

  Win8提示“已禁用IME”怎么办编程最近使用Win8的网友遇到了一个问题,问小编:Win8提示“已禁用IME”怎么办?小编就在这篇文章跟大家分享一下Win8提示“已禁用 I
2023-06-06

Discuz提示“密码错误次数过多,请15分钟后重新登陆”问题解决方法

在使用论坛过程中,有时候会遇到这样的提示&ldquo编程客栈;密码错误次数过多,请 15 分钟后重新登陆”,因为忘记密码而登陆次数过多被锁定。当然也不排除有人利用暴力破解工具一直在爆破各种管理员密码,从而导致管理员或用户不能登录
2022-06-12

登录织梦后台提示用户名不存在的解决方法介绍

这下着实ypkTHEYpE让我心惊胆战,因为我的网站已经建了一年半多了,承蒙各路搜索引擎看得起,有一定的流量。一年多的时间都耗在这个http://www.cppcns.com网站上面。 出了问题后,第一时间是在网上搜索相关的教程,及解决的方
2022-06-12

mysql 的root 用户无法授权,navicat 远程授权提示1044解决方案

先看解决方案#------------mysql root 用户无法赋权问题解决 --------1,登录 mysql -u root -p2,use mysql; 选择mysql数据库3,执行以下操作(查询用户的赋权权限,更改赋权权限 ,刷新生效)mysq
mysql 的root 用户无法授权,navicat 远程授权提示1044解决方案
2020-10-01

win8系统修改用户头像提示用户头像错误的故障原因及解决方法

Win8系统可以给账户设置用户头像,让账户变得更有个性。有些用户修改用户头像时发生错误,提示设置用户头像失败,请再试一次。这是怎么回事呢?导致win8系统无法修改用户头像的原因有很多种,大家可以尝试下面教程内容解决问题。Win8无法修改用户
2022-06-04

win7用户目录多个Administrator.xxx怎么办?解决方法

安装Ghost win7系统后发现,c:/users有两个目录,一个是Administrator, 一个Administratpythonor.UCRWXdw7RTD。但是启动命令行发现使用的目录是:C:UsersAdministrator
2023-05-20

win10系统运行wegame提示用户账户控制的解决办法是什么

今天给大家介绍一下win10系统运行wegame提示用户账户控制的解决办法是什么。文章的内容小编觉得不错,现在给大家分享一下,觉得有需要的朋友可以了解一下,希望对大家有所帮助,下面跟着小编的思路一起来阅读吧。在win10系统中运行wegam
2023-06-28

编程热搜

目录