在React hook中使用防抖节流

227 阅读1分钟

在React hook中使用防抖节流

防抖和节流

先来介绍一下防抖和节流

防抖:事件触发后延迟n秒在执行,如果在这n秒内再次触发则重新计时。即在一段时间内只允许事件执行一次,常用于表单提交,输入框防抖

节流:事件触发后延迟n秒在执行,并且在这n秒内再次触发事件时不允许执行。即减少一段时间内事件触发的频率,常用与监听滚动条滚动,鼠标移动,窗口大小变化

依据上面的定义可以手写一个防抖和节流

防抖函数

import { useRef, useCallback, useEffect } from 'react'
type FnType = (...arg: any[]) => any
interface RefType {
  fn: FnType
  timer: NodeJS.Timeout | null
}

function useDebounce(fn: FnType, delay: number, dep: any[] = []) {
  //  使用 useRef 的目的是:保留上一次的timer,以至于让 if 语句走通,然后清除上一次的 timer
  // 否则,没有清除定时器,达不到防抖效果
  const { current } = useRef<RefType>({ fn, timer: null })

  return useCallback((...args: any) => {
    if (current.timer) {
      clearTimeout(current.timer)
    }
    current.timer = setTimeout(() => {
      current.fn(...args)
    }, delay)
  }, dep)
}

export default useDebounce

节流函数

import { useRef, useCallback, useEffect } from 'react'
type FnType = (...arg: any[]) => any
interface RefType {
  fn: FnType
  timer: NodeJS.Timeout | null
}

/**
 * 节流函数
 * @param fn
 * @param delay
 * @param dep
 * @returns
 */
function useThrottle(fn: FnType, delay: number, dep: any[] = []) {
  //  使用 useRef 的目的是:保留上一次的timer,以至于让 if 语句走通,然后清除上一次的 timer
  // 否则,没有清除定时器,达不到防抖效果
  const { current } = useRef<RefType>({ fn, timer: null })

  return useCallback((...args: any[]) => {
    if (!current.timer) {
      current.timer = setTimeout(() => {
        current.timer = null
      }, delay)
      current.fn(...args)
    }
  }, dep)
}

export default useThrottle