今天在学习其他项目的时候看到了别人写的hooks,学习了之后自己也写了一个。

目标:可以传入三个参数,一个是click,一个是doubleClick,一个是time,分别代表单击之后执行的事件,双击之后执行的事件以及在点击多久后执行click单击事件。

返回:返回一个函数,该函数可以用于点击事件。

案例实现

javascript

import { useCallback,useRef } from "react";

export default function useDoubleClick({click,doubleClick,time = 300}){
    const clickTimeOut=useRef();
    //清除点击计时器
    const clearClickTimeOut=()=>{
        if(clickTimeOut.current){
            clearTimeout(clickTimeOut.current);
            clickTimeOut.current=null;
        }
    }
    //使用useCallback,优化返回值
    return useCallback((e)=>{
        clearClickTimeOut();
        if(e.detail===1){
            clickTimeOut.current=setTimeout(()=>{
                click&&click(e);
            },time);
        }else if(e.detail%2===0){
            doubleClick&&doubleClick(e);
        }
    },
    [click,doubleClick,time])
}

typescript

import { useCallback, useRef } from "react";

type Props ={
    time?:number,
    click?:Function,
    doubleClick:Function
}

export default function useDoubleClick ({click ,doubleClick ,time=300}:Props)  {
    const clickTimeOut=useRef<any>();
    
    const clearClickTimeOut =()=>{
        if(clickTimeOut){
            clearTimeout(clickTimeOut.current);
            clickTimeOut.current=null;
        }
    }
    
    return useCallback((e:React.MouseEvent<HTMLElement>)=>{
        clearClickTimeOut()
        if(click && e.detail===1){
            clickTimeOut.current= setTimeout(()=>{
                click(e)
            },time)
        }
        if(e.detail%2===0){
            doubleClick(e)
        }
    },[click,doubleClick,time])
}

使用案例

import useDoubleClick from "./hooks/useDoubleClick.js"

export default () => {
    const clickEvent = useDoubleClick({
        click: () => { console.log('单击') },
        doubleClick: () => { console.log('双击') },
        time:0
    })
    return (
        <>
            <button onClick={clickEvent}>点击事件</button>
        </>
    )
}

对于该hooks的进一步理解

Q:为什么使用ref存储状态而不是使用state?

useState用于存储状态,react会监听state的变化,如果state变化会导致该函数的re-render,我们并不希望该函数进行大量的re-render,因为他仅仅用于数据处理而非展示。同样的,我们也使用了useCallback来进行代码优化,用于减少多余的函数创建。

Q:这里的time究竟是什么意思,是单击之后的时间间隔内再单击会变成双击吗?

注意,这里的time并不是时间间隔,而是单击之后多久会执行click,如果把time设置的特别短(或者就是0),那么我们在进行一次双击事件后两个点击事件都会执行打印:单击 双击双击事件的时间由react内部封装的事件来决定(好像默认300ms?不是很确定),不过我们也可以修改来自己决定。

Q:这里的callback的原理是什么?

当一个组件被re-render之后,如果不使用useCallback,每一次组件的re-render都会进行一次函数的创建,降低了效率。

Q.E.D.