这篇文章主要介绍“ahooks怎么解决用户多次提交问题”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“ahooks怎么解决用户多次提交问题”文章能帮助大家解决问题。
场景
试想一下,有这么一个场景,有一个表单,你可能多次提交,就很可能导致结果不正确。
解决这类问题的方法有很多,比如添加 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 的拦截器。
具体的做法如下:
第一步,定义几个重要的辅助函数。
这里我认为,如果有需要的话,可以暴露一个 API 给开发者进行自定义重复的规则。这里我们先根据请求方法、url、以及参数生成唯一的 key 去做。
function generateReqKey(config) {
const { method, url, params, data } = config;
return [method, url, Qs.stringify(params), Qs.stringify(data)].join("&");
}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);
}
});
}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 完成了自动取消重复请求的功能。
关于“ahooks怎么解决用户多次提交问题”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注天达云行业资讯频道,小编每天都会为大家更新不同的知识点。