今天在学习其他项目的时候看到了别人写的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.