0


react防抖和节流hooks封装

一、防抖和节流概述

防抖(debounce)和节流(throttle)是前端经常用到的工具函数。

在进行窗口的resize、scroll,输入框内容校验等操作时,如果事件处理函数调用的频率无限制,会加重浏览器的负担,导致用户体验非常糟糕。此时我们可以采用debounce(防抖)和throttle(节流)的方式来减少调用频率,同时又不影响实际效果。

通常情况下,我们习惯于使用

lodash

提供的工具函数,那么如何自己封装防抖节流的hooks?

首先了解下概念:

  • 防抖: 维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。
  • 节流: 维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,会判断是否有延迟调用函数未执行,有则返回,没有则设定在delay时间后触发函数

1、函数防抖

当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。

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

2、函数节流

当持续触发事件时,保证一定时间段内只调用一次事件处理函数。

function throttle(fn, ms) {            
    let timer;        
    return function(...args) {                
        if (timer) return;
        canRun = false;
        timer = setTimeout(() => { 
            fn(...args);
            timer = null;
        }, ms);          
    }        
}        

二、react当中防抖细节

防抖函数必须在只执行一次的位置调用。在类组件中,放在

constructor

里或者变量函数生成的时候都可以,因为类组件只会初始化一次,后续组件中绑定的函数永远是不变的,因此依据闭包原理保存下来的状态会起作用。

而在函数式组件中,每次render时,内部函数会重新生成并绑定到组件上去。当组件只有一个state会影响

render

时,我们

  1. 狂点按钮,
  2. 只会触发点击事件,不会重新渲染,
  3. 当前组件绑定的事件函数没有变化,防抖函数是同一个,因此防抖起作用

但是当有其他

state

影响渲染后

  1. 狂点按钮
  2. 触发事件,不重新渲染
  3. count2发生变化,重新渲染
  4. handleClick重新生成并绑定到组件,
  5. 原有函数失效,防抖失效,原有函数延迟一定后执行
  6. counter1发生变化

流程的对比就是这样了,现在你明白为什么正常的防抖函数不能用在

reack hook

里了么?

那么,怎么实现

react hook

防抖呢?核心思想就是,保证每次渲染时,绑定到组件上的函数是同一个防抖函数。

防抖hook

import { useCallback, useEffect, useRef } from 'react';
export interface UseRefParams {
  fn: (_args: any) => void;
  timer: ReturnType<typeof setTimeout> | null;
}
// React anti shake function
export const useDebounce = (fn: (_args: any) => void, delay = 2000) => {
  const { current } = useRef<UseRefParams>({ fn, timer: null });
  useEffect(() => {
    current.fn = fn;
  }, [current, fn]);
  return useCallback(
    (args: any) => {
      if (current.timer) {
        clearTimeout(current.timer);
      }
      current.timer = setTimeout(() => {
        current.fn(args);
      }, delay);
    },
    [current, delay]
  );
};

三 、节流Hook

在react当中节流注意细节与防抖一样,这里不做陈述,直接上代码:

import { useCallback, useEffect, useRef } from 'react';
export interface UseRefParams {
  fn: (_args: any) => void;
  timer: ReturnType<typeof setTimeout> | null;
}

// React throttling function
export const useThrottle = (fn: (_args: any) => void, delay = 2000) => {
  const { current } = useRef<UseRefParams>({ fn, timer: null });
  useEffect(
    function () {
      current.fn = fn;
    },
    [current, fn]
  );
  return useCallback(
    function f(args: any) {
      if (!current.timer) {
        current.timer = setTimeout(() => {
          current.timer = null;
        }, delay);
        current.fn(args);
      }
    },
    [current, delay]
  );
};

本文转载自: https://blog.csdn.net/sinat_36728518/article/details/140694862
版权归原作者 任磊abc 所有, 如有侵权,请联系我们删除。

“react防抖和节流hooks封装”的评论:

还没有评论