不知道有多少人,简单的写了防抖、节流函数,然后遇到在 react hook 里失效的情况。
失效的原因: 每次 render 时,内部 函数会重新生成 并绑定到组件上去。
解决方案: 也很简单,使用 useCallback ,依赖传入空数组,保证 useCallback 永远返回同一个函数。
上面呢,算是这个文章的一个契机吧。
关于手写防抖和节流的思路,个人认为关键在于都是对 闭包 和 高阶函数 的应用,以这个为切入点去思考,手写的时候就不会脑子一片空白了。
触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
这可以用,但并不够好。想要进阶更高级的工程师,就需要将问题再想深一层,考虑到更复杂的情况,从而自身得到成长。
关于防抖函数还有功能更丰富的版本,可以看下 lodash 的 debounce 函数
连续触发事件但是在 n 秒中只执行一次函数
把两个整合一下,根据场景、需求等来决定,最后是否需要事件停止触发后定时器执行函数。
有个地方有人可能有疑问,为什么没去用 useRef 去保存 timeOut 呢?
有人可能会认为这会有问题:因为每次组件重新渲染,都会执行一遍所有的 hooks,这样 useDebounce 高阶函数里面的 timeOut 就不能起到缓存的作用(在 useDebounce 里 console.log(timeOut),每次 render 时都打印出 null)。所以 timeOut 不可靠,防抖的核心就被破坏了。
但是呢,如果你在里面的函数 debounce 里 console.log(timeOut) 会发现,打印出来的,就是之前的 timeOut ,所以是没问题的。
最后,写的过程中,ts 才是我真正花费时间思考的地方。完成后,有点微妙的满足感。
说明 f1 是个“高阶”函数。f1()() 说明 f1() 执行的结果也是个函数,假设为 f2。
则
f1()()
表示 f2()
那么, f1()()() 可表示为
f2()()
说明 f2() 的返回值右是一个函数。
为了表达清晰,说的有点绕。
总结,f1() 返回值是一个函数,这个函数的返回值依然是函数。