前言
我一直认为, 自定义 Hooks
是一个食之无味弃之可惜,用来炫技的东西。
事实并非如此。
事件起因
问题
今天测试遇到一个问题,一个按钮多次点击多次提交,导致资源浪费。
尝试解决
Taro-UI AtButton 的 loading 参数
第一步我想到的解决方案是 Taro-UI
的 AtButton
中的 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
思考
既然不是节流的问题,那一定是代码中哪一段出现了问题。首先我就想到了 Hooks
的 render
机制,实际上整个 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
后,由于面试过那么几家公司更偏算法的提问,忘记了立足之本。
勿自大、勿狭隘、勿因业务简单就不再深挖。
多学、多看、多写、多听、多钻研。