自定义 Hooks 之 3个自定义防抖 Hooks 的实现原理

发布于 2024-11-17 11:36:07 字数 4753 浏览 0 评论 0

前言

本文通过实现 useDebounceFn、useDebounce、useDebounceEffect 3 种自定义防抖 Hooks,来介绍在日常开发过程中自定义 Hooks 的思路及实现,帮助大家完成通用 Hooks 来提高开发效率。

防抖

防抖的概念已经司空见惯了,这里稍作简单介绍:

  • 举例:输入事件,原本连续输入 10 个字符会触发 10 次事件,使用防抖可以在间断输入时才触发一次事件
  • 防抖:某连续事件可通过防抖定义为超过指定时间事件才触发

一个简单的防抖可以通过闭包+定时器实现:

function debounce(fn, delay) {
  let timer = null

  return function (...args) {
    // 下一次触发时清空定时器,这样事件就要等新的定时器结束后才执行了
    if (timer) {
      clearTimeout(timer)
    }

    timer = setTimeout(() => {
      fn.call(this, ...args)
    }, delay)
  }
}

在 React 函数组件内防抖

真实场景

比如有一个这样的需求,是在更新 Input 输入框时,搜索数据。

类似的功能图如下:

image.png

通过 React useEffect,简单的 demo 实现如下:

import { Input } from 'antd'
import { useEffect, useState } from 'react'
import './App.css'

function App() {
  const [val, setVal] = useState('')

  const onSearch = (val) => {
    console.log('搜索', val || '全部')
  }

  const onChange = (e) => setVal(e.target.value)

  // 当 val 发生变化时,请求搜索数据
  useEffect(() => {
    onSearch(val)
  }, [val])

  return (
    <div className='App'>
      <Input value={val} placeholder='请输入' onChange={onChange} allowClear />
    </div>
  )
}

这时可以看到,首次进入页面,会发起 2 次查询全部的搜索数据请求,然后每次输入框更新,都会发起搜索数据的请求。

image.png

正常来说是不是我们在 onSearch 事件,加入 debounce,就能够做到当输入操作停顿指定时间后,才发起搜索数据的请求。

这里需要注意的是要加上 useCallback,来避免重复渲染导致的延时事件重复触发问题。

将 onSearch 方法用 debounce + useCallback 封装后,可以实现防抖效果。

const onSearch = useCallback(
  debounce((val) => {
    console.log('搜索', val || '全部')
  }, 500),
  []
)

image.png

接下来就是把防抖的逻辑按照 3 个不同的思路封装成不同的自定义 Hooks。

useDebounceFn

第一个自定义防抖 Hooks 的思路是,将上述 debounce + useCallback 封装为通用的自定义 Hooks useDebounceFn,实现一个有防抖效果的函数。

使用方式: useDebounceFn(fn1, options)

interface DebounceOptions {
  wait?: number;
}

const useDebounceFn = (fn: (...args: any) => any, options: DebounceOptions) => {
  return useCallback(debounce(fn, options.wait), [])
}

const onSearch = useDebounceFn(
  (val) => {
    console.log('搜索', val || '全部')
  },
  {
    wait: 500,
  }
)

useDebounce

第二个自定义防抖 Hooks 的思路是创建一个新 state,setState 用 useDebounceFn 封装,返回一个具有防抖效果的 state。

使用方式: useDebounce(state, options)

function useDebounce<T>(value: T, options: DebounceOptions) {
  const [debounced, setDebounced] = useState(value)

  const update = useDebounceFn((value) => {
    setDebounced(value)
  }, options)

  useEffect(() => {
    update(value)
  }, [value])

  return debounced
}

将 useEffect 的依赖项改成 useDebounce 返回的 state,同样可以实现搜索防抖:

const debounceVal = useDebounce(val, { wait: 500 })
const onSearch = (val: string) => {
  console.log('搜索', val || '全部')
}

// 当 debounceVal 发生变化时,请求搜索数据
useEffect(() => {
  onSearch(debounceVal)
}, [debounceVal])

useDebounceEffect

第三个自定义防抖 Hooks 的思路是创建一个新 state,setState 用 useDebounceFn 封装,依赖更新时防抖更新 state,新 state 更新时执行副作用,这时副作用就防抖执行了,实现一个具有防抖效果的 useEffect。

使用方式: useDebounceEffect(effect, deps, options)

function useDebounceEffect(
  effect: EffectCallback,
  deps: DependencyList,
  options: DebounceOptions
) {
  const [debounced, setDebounced] = useState({})

  const update = useDebounceFn(() => {
    setDebounced({})
  }, options)

  useEffect(() => {
    update()
  }, deps)

  useEffect(effect, [debounced])
}

将 useEffect 改成 useDebounceEffect,就可以实现搜索防抖:

useDebounceEffect(
    () => {
      onSearch(val)
    }
    [val],
    { wait: 500 }
  )

小结

大家应该比较清晰自定义防抖 Hooks 的实现思路了,可以通过这个思路给自己组件内的通用逻辑封装成通用的 Hooks 啦。

本文实现的 useDebounceFn、useDebounce、useDebounceEffect 3 种防抖 Hooks,可以直接下载 ahooks 使用。

参考资料

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

0 文章
0 评论
23 人气
更多

推荐作者

linfzu01

文章 0 评论 0

可遇━不可求

文章 0 评论 0

枕梦

文章 0 评论 0

qq_3LFa8Q

文章 0 评论 0

JP

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文