hook,什么,防抖函数?

Posted 前端e站

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hook,什么,防抖函数?相关的知识,希望对你有一定的参考价值。

防抖(debounce)是前端经常用到的一个工具函数,也是在面试中常常被问到的一个问题。

防抖函数

经典的防抖函数:

function debounce(fn, ms) 
  let timer;
  return function(...args) 
    if (timer) 
      clearTimeout(timer)
    
    timer = setTimeout(() => 
      fn(...args)
      timer = null;
    , ms);
  

react hooks版的防抖函数

export default function() 
  const [counter, setCounter] = useState(0);

  const handleClick = useDebounce(function() 
    setCounter(counter + 1)
  , 1000)

  return <div style= padding: 30 >
    <Button
      onClick=handleClick
    >click</Button>
    <div>counter</div>
  </div>

实际使用的时候,是这样的

export default function() 
  const [counter1, setCounter1] = useState(0);
  const [counter2, setCounter2] = useState(0);

  const handleClick = useDebounce(function() 
    console.count('click1')
    setCounter1(counter1 + 1)
  , 500)

  useEffect(function() 
    const t = setInterval(() => 
      setCounter2(x => x + 1)
    , 500);
    return clearInterval.bind(undefined, t)
  , [])


  return <div style= padding: 30 >
    <Button
      onClick=function() 
        handleClick()
      
    >click</Button>
    <div>counter1</div>
    <div>counter2</div>
  </div>

当引入一个自动累加counter2就开始出问题了。这时很多候选人就开始懵了,有的候选人会尝试分析原因。只有深刻理解react hooks在重渲染时的工作原理才能快速定位到问题(事实上出错不要紧,能够快速定位问题的小伙伴才是我们苦苦寻找的)。

你可能会这样修改

const handleClick = useDebounce(function() 
    console.count('click1')
    setCounter1(x => x + 1)
, 500)

还可能这样修改

function useDebounce(fn, delay) 
  return useCallback(debounce(fn, delay), [])

在配合setCounter1(x => x + 1)修改的情况下,可以得到正确的结果。

但显然你仔细测试一下,还是没有真正的解决问题。

那么,问题在哪里呢?

function useDebounce(fn, time) 
  console.log('usedebounce') // 打印这里看一下
  return debounce(fn, time);

控制台开始疯狂的输出log...,大脑在飞快的思考。

每次组件重新渲染,都会执行一遍所有的hooks,这样debounce高阶函数里面的timer就不能起到缓存的作用(每次重渲染都被置空)。timer不可靠,debounce的核心就被破坏了。

这才是优化

// 加入缓存机制
function useDebounce(fn, delay, dep = []) 
const  current  = useRef( fn, timer: null );
  useEffect(function () 
    current.fn = fn;
  , [fn]);
return useCallback(function f(...args) 
if (current.timer) 
      clearTimeout(current.timer);
    
    current.timer = setTimeout(() => 
      current.fn.call(this, ...args);
    , delay);
  , dep)

// 
function useThrottle(fn, delay, dep = []) 
const  current  = useRef( fn, timer: null );
  useEffect(function () 
    current.fn = fn;
  , [fn]);
return useCallback(function f(...args) 
if (!current.timer) 
      current.timer = setTimeout(() => 
delete current.timer;
      , delay);
      current.fn.call(this, ...args);
    
  , dep);

react hooks可以帮助我们把一些常用的状态逻辑沉淀下来,你学会了吗?

 

以上是关于hook,什么,防抖函数?的主要内容,如果未能解决你的问题,请参考以下文章

hook,什么,防抖函数?

useEffect中防抖为什么不起作用?react hooks中如何写防抖?

useEffect中防抖为什么不起作用?react hooks中如何写防抖?

手写防抖、节流 hook(ts版)

react hooks之useDebounce useThrottle

JS基础-防抖和节流