当组件中需要给外部传入的单个ReactNode节点添加点击事件,以便简洁组件外代码。可以使用 cloneElement 进行绑定一个默认点击事件。
import React, { type ReactNode, useRef } from 'react';
/**
* 自定义Hook,用于处理元素点击事件,防止重复点击
* @param triggerNode 触发点击的React节点
* @param onClick 点击事件回调函数
* @param stopPropagation 是否阻止事件冒泡,默认为true
* @param debounceMs 防重复点击的时间间隔,默认为300ms
* @returns 克隆后的React元素,带有防重复点击的onClick处理函数
*/
const useNodeClick = (
triggerNode?: ReactNode,
onClick?: (event: React.MouseEvent) => void,
stopPropagation = true,
debounceMs = 300
) => {
// 检查是否为单个React元素
const isOnly = React.isValidElement(triggerNode)
// 使用ref记录上次点击的时间戳
const lastClickTime = useRef(0)
// 如果不是单个元素,给出警告
if (!isOnly) {
console.warn('请使用单元素,单元素默认click事件不冒泡', triggerNode)
}
// 如果不是单个元素,直接返回原始节点
if (!isOnly) {
return triggerNode
}
// 克隆元素并添加防重复点击的onClick处理函数
return React.cloneElement(triggerNode as React.ReactElement<any>, {
onClick: (event: React.MouseEvent) => {
// 获取当前时间戳
const now = Date.now()
// 如果距离上次点击时间小于设定的间隔时间,则阻止点击
if (now - lastClickTime.current < debounceMs) return
// 更新上次点击时间为当前时间
lastClickTime.current = now
// 根据参数决定是否阻止事件冒泡
if (stopPropagation) {
event.stopPropagation();
}
// 执行传入的点击回调函数
if (onClick) {
onClick(event);
}
// 执行子元素原有的onClick事件
const child = triggerNode as React.ReactElement<any>;
if (child.props.onClick) {
child.props.onClick(event);
}
},
})
}
export default useNodeClick