react hooks 节流(throttle)失效?自定义 Hooks 原来是这么玩儿的?!

前言

我一直认为, 自定义 Hooks 是一个食之无味弃之可惜,用来炫技的东西。

事实并非如此。

事件起因

问题

今天测试遇到一个问题,一个按钮多次点击多次提交,导致资源浪费。

尝试解决

Taro-UI AtButton 的 loading 参数

第一步我想到的解决方案是 Taro-UIAtButton 中的 loading 功能。让我感到遗憾的是, Taro-UI 并不完善。添加 loading 后竟然没有禁用 click 事件。

手动添加 flag 禁用

那么只能自己来了,添加了 flag ,通过 flag 判断是否已经提交。但由于一些其他问题,这样做并不够,因为提交后他还是可以再次提交。

节流处理 throttle

那我祖传的 throttle 就派上用场了,通过 throttle 限制点击频率。

function throttle(fn, gapTime) {
  let _lastTime = null;

  return function () {
    let _nowTime = + new Date()
    if (_nowTime - _lastTime > gapTime || !_lastTime) {
      fn();
      _lastTime = _nowTime
    }
  }
}

const App = () => {
    ...
    const submit => throttle(() => {...}, 1000)
}
复制代码

??? 我的节流失灵了?

刚好项目中有 lodash ,我写的 throttle 有问题, lodash 总不能有问题吧?

import _ from 'lodash'

const App = () => {
    ...
    const submit => _.throttle(() => {...}, 1000)
}
复制代码

为何还是不行 (((

怀疑人生 emmm

思考

既然不是节流的问题,那一定是代码中哪一段出现了问题。首先我就想到了 Hooksrender 机制,实际上整个 function 重新执行了,那么显而易见的 throttle 变为了新的 throttle,那么问题大概率出现在这里。

解决方案

献上代码:

定义 useThrottle

import _ from "lodash"
import { useRef, useCallback, useEffect } from 'react'

export function useThrottle(cb, delay) {
  const options = { leading: true, trailing: false };
  const cbRef = useRef(cb);

  useEffect(() => { cbRef.current = cb; });
  
  return useCallback(
    _.throttle((...args) => cbRef.current(...args), delay, options),
    [delay]
  );
}
复制代码

使用 useThrottle

import { useThrottle } from 'xxx/useUtil'

const App = () => {
    ...
    const submit => useThrottle(() => {...}, 1000)
}
复制代码

这样我们在组件重新渲染时,将不会导致 throttle 的指向更新,因此可以实现节流功能。

两个我不常用的 Hooks (也许应该用起来)

挖个坑,后续将对这两个 Hooks 进行深挖,敬请期待。

useRef

返回一个生命周期内不会改变指向的对象。

类似类组件的实例属性。

useRef 不会触发组件的重新渲染。

useCallback

传入的函数只有当依赖发生变化时才会更新。

总结

自学习 React 后,由于面试过那么几家公司更偏算法的提问,忘记了立足之本。

勿自大、勿狭隘、勿因业务简单就不再深挖。

多学、多看、多写、多听、多钻研。

Guess you like

Origin juejin.im/post/7034071485933158408