React Native防止重复点击

项目中遇到了点击按钮重复提交的问题,防止重复点击首先是想到的是给点击事件一个定时,下次触发的条件是要距离上一次点击的时间大于N秒的之后才能再执行。

typescript 复制代码
// 防重复点击函数
export const preventRepeatPress = {
	lastPressTi1me: 0,  	//  上次点击时间      
	repoTime: 2000,   		//  默认间隔时间2000  
	onPress(callback: () => void, waitTime: number = 2000) {
		let currTime = Date.now();
		if (currTime - this.lastPressTime > this.repoTime) {
			this.lastPressTime = currTime;
			this.repoTime = waitTime;         
			callback && callback();
		}
	},
};

在组件上的点击函数onPress中使用preventRepeatPress方法

typescript 复制代码
<Button title="点击按钮" onPress={() => preventRepeatPress.onPress(() => fun())} /> 

在点击的时候可以传入设置间隔时间进行单独控制

typescript 复制代码
() => preventRepeatPress.onPress(() => onCredit(),5000)

第二使用 setTimeout 函数

需要注意的是 timeout 需要放在全局也就是函数外部,否则的话每次调用 timeout 都会重新初始化导致防抖函数失去效果。

定义一个名为 debouncePlus 的函数,它接受一个函数 func,一个等待时间 wait(默认为 1000 毫秒)和一个 immediate 参数

typescript 复制代码
// 定义一个变量 timeout,用于存储定时器的标识,变量作用域需要在函数外部
let timeout: string | number | NodeJS.Timeout | null | undefined = null;

export const debouncePlus = (
	func: { apply: (arg0: any, arg1: IArguments) => void; },
	wait: number | undefined = 1000,
	immediate: any
) => {
	// 变量 result,用于存储函数执行的结果
	let result: any;
	// 定义一个内部函数 debounced,它将作为防抖后的函数被返回
	let debounced = function (this: any) {
		// 获取当前函数执行的上下文(this 指向)
		let context = this;
		// 获取传递给当前函数的参数
		let args = arguments;

		// 如果定时器已经存在,清除之前的定时器
		if (timeout) clearTimeout(timeout);
		// 如果 immediate 为真
		if (immediate) {
			// 如果 timeout 为 null,说明是第一次调用,应该立即执行函数
			let callNow = !timeout;
			// 设置一个新的定时器,在等待时间之后将 timeout 置为 null
			timeout = setTimeout(function () {
				timeout = null;
			}, wait);
			// 如果应该立即执行,则调用原始函数,并将结果存储在 result 中
			if (callNow) result = func.apply(context, args);
		}
		// 如果 immediate 为假
		else {
			// 设置一个新的定时器,在等待时间之后执行原始函数
			timeout = setTimeout(function () {
				func.apply(context, args);
			}, wait);
		}
		// 返回函数执行的结果(如果是 immediate 模式,可能是立即执行的结果;否则可能是 null)
		return result;
	};

	// 给 debounced 函数添加一个 cancel 方法,用于取消正在等待执行的定时器
	debounced.cancel = function () {
		clearTimeout(timeout);
		timeout = null;
	};

	// 返回防抖后的函数
	return debounced;
};

第三使用 hook

typescript 复制代码
/**
 * 防抖hook
 *   
 const { run } = useDebounceFn(
    () => {setValue(value + 1)},
    {wait: 500,},
  );
 */
import { useEffect, useMemo, useRef } from 'react';
import { debouncePlus } from './debounce-plus';

const isDev = process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test';
const isFunction = (value: unknown): value is (...args: any) => any => typeof value === 'function';

interface DebounceOptions {
  wait?: number;
  leading?: boolean;
  trailing?: boolean;
  maxWait?: number;
}

type noop = (...args: any[]) => any;

function useDebounceFn<T extends noop>(fn: T, options?: DebounceOptions) {
  if (isDev) {
    if (!isFunction(fn)) {
      console.error(`useDebounceFn expected parameter is a function, got ${typeof fn}`);
    }
  }

  const fnRef = useLatest(fn);

  const wait = options?.wait ?? 1000;

  const debounced = useMemo(
    () =>
      debouncePlus(
        (...args: Parameters<T>): ReturnType<T> => {
          return fnRef.current(...args);
        },
        wait,
        options,
      ),
    [],
  );

  useUnmount(() => {
    debounced.cancel();
  });

  return {
    run: debounced,
    cancel: debounced.cancel,
    // flush: debounced.flush,
  };
}

export default useDebounceFn;


export const useUnmount = (fn: () => void) => {
  if (isDev) {
    if (!isFunction(fn)) {
      console.error(`useUnmount expected parameter is a function, got ${typeof fn}`);
    }
  }

  const fnRef = useLatest(fn);

  useEffect(
    () => () => {
      fnRef.current();
    },
    [],
  );
};

export function useLatest<T>(value: T) {
  const ref = useRef(value);
  ref.current = value;

  return ref;
}

有好的思路欢迎评论交流

相关推荐
哈__2 小时前
React Native 鸿蒙跨平台开发:PixelRatio 像素适配
javascript·react native·react.js
用户6387994773052 小时前
每组件(Per-Component)与集中式(Centralized)i18n
前端·javascript
zerosrat2 小时前
从零实现 React Native(2): 跨平台支持
前端·react native
DarkLONGLOVE2 小时前
Vue组件使用三步走:创建、注册、使用(Vue2/Vue3双版本详解)
前端·javascript·vue.js
DarkLONGLOVE2 小时前
手把手教你玩转Vue组件:创建、注册、使用三步曲!
前端·javascript·vue.js
冴羽4 小时前
2026 年前端必须掌握的 4 个 CSS 新特性!
前端·javascript·css
狗头大军之江苏分军4 小时前
告别旧生态:Ant Design 6 不再支持 IE 与现代前端趋势解读
前端·javascript·后端
Highcharts.js4 小时前
Highcharts Grid 表格/网格安装 |官方安装文档说明
开发语言·javascript·表格组件·highcharts·官方文档·安装说明·网格组件
lili-felicity4 小时前
React Native 鸿蒙跨平台开发:LayoutAnimation 实现鸿蒙端按钮点击的缩放反馈动画
react native·react.js·harmonyos
3824278275 小时前
表单提交验证:onsubmit与return详解
前端·javascript·html