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

news2024/12/23 22:09:30

前言—

本文通过实现 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 输入框时,搜索数据。

类似的功能图如下:

通过 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 次查询全部的搜索数据请求,然后每次输入框更新,都会发起搜索数据的请求。

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

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

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

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

接下来就是把防抖的逻辑按照 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[1] 使用。

参考资料—

[1]

ahooks: https://ahooks.js.org/zh-CN/hooks/use-debounce

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/418221.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

00后也太卷了吧!进厂起薪18K,原来面试时候都说了这些......

都说00后躺平了&#xff0c;但是有一说一&#xff0c;该牛的还是牛。 这不&#xff0c;前段时间公司来了个00后&#xff0c;工作都没两年&#xff0c;跳槽起薪18K。本来还以为是个年少有为的技术大牛呢&#xff0c;结果相处一个月下来发现技术也就那样。 问起他是如何做到和老…

Java Web学习路线

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;努力输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐所属专栏&#xff1a;Java Web ⭐如果觉得文章写的不错&#xff0c;欢迎点个关注一键三连&#x1f609;有写的不好的地方也欢迎指正&a…

(四)栈—中缀表达式转后缀表达式

一、基本介绍 二、应用实例 将中缀表达式"1((23)x4)-5" 转换为 后缀表达式"1 2 3 4 x 5 -" 思路&#xff1a; 1.初始化两个栈&#xff1a;运算符栈s1和存储中间结果的栈s2&#xff1b; 2.从左至右扫描中缀表达式&#x…

【c++初阶】第九篇:vector(常用接口的使用 + 模拟实现)

文章目录vector介绍vector的使用vector的定义vector iterator(迭代器) 的使用begin和endrbegin和rendvector 空间增长问题size和capacityreserve和resize&#xff08;重点&#xff09;测试vector的默认扩容机制emptyvector的增删查改push_back和pop_backinsert和erasefindswapo…

GPT-4创造者:第二次改变AI浪潮的方向

OneFlow编译 翻译&#xff5c;贾川、杨婷、徐佳渝 编辑&#xff5c;王金许 一朝成名天下知。ChatGPT/GPT-4相关的新闻接二连三刷屏朋友圈&#xff0c;如今&#xff0c;这些模型背后的公司OpenAI的知名度不亚于任何科技巨头。 不过&#xff0c;就在ChatGPT问世前&#xff0c;Ope…

Verilog Tutorial(10)如何实现可复用的设计?

写在前面在自己准备写verilog教程之前&#xff0c;参考了许多资料----FPGA Tutorial网站的这套verilog教程即是其一。这套教程写得不错&#xff0c;只是没有中文&#xff0c;在下只好斗胆翻译过来&#xff08;加了自己的理解&#xff09;分享给大家。这是网站原文&#xff1a;h…

【敬伟ps教程】平移、缩放、移动、选区

文章目录平移抓手工具旋转抓手缩放工具移动工具详解选区选区工具详解平移 抓手工具 当打开一张大图时&#xff0c;可以通过修改底部的百分比或使用抓手工具&#xff08;H或在任何时候按住空格键来使用抓手工具&#xff09;来查看更多细节 使用抓手工具时滚动所有打开的文档&…

几何的显式表示 - 曲线和曲面

点云&#xff1a;list of points&#xff08;x, y, z&#xff09; 将点云变成多边形的面&#xff0c;从而在计算机中输出多边形网格&#xff1a;Polygon Mesh 就是 拆成小三角 贝塞尔曲线 定义曲线只要满足起止点即可&#xff0c;P1&#xff0c;P2决定了它要往哪个方向弯 de Ca…

STM32 HAL库PID控制电机 第三章 PID控制双电机

STM32 HAL库PID控制电机 第三章 PID控制双电机 注:本文含全部PID控制代码,保证可以运行,如不能运行可以留言回复 1 基础配置 1.1 编码器电路图及配置 引脚定时器通道PA0TIM2_CH1PA1TIM2_CH2PB6TIM4_CH1PB7TIM4_CH2因此需要把TIM2、TIM4配置为编码器模式。在STM32CubeMX中…

如何在react中处理报错

本文为 360 奇舞团前端工程师翻译 原文地址&#xff1a;https://www.developerway.com/posts/how-to-handle-errors-in-react我们都希望我们的应用能稳定、完美运行&#xff0c;并且能够考虑到每一个边缘情况。但是现实情况是&#xff0c;我们是人&#xff0c;是人就会犯错&…

【区块链】走进web3的世界-DApp如何快速接入wall

在web3中&#xff0c;wall是您进入区块链的一个标识&#xff0c;每个用户使用的wall都不近相同&#xff0c;因此接入更多的wall是很有必要的&#xff0c;从用户角度来说&#xff0c;非必要情况下&#xff0c;我是不愿意去额外下载wall的。因此今天我们来聊一下&#xff0c;DApp…

手把手教你搭建 Docker API 未授权漏洞环境

环境&#xff1a;ubuntu 16.04 我是在虚拟机中安装了ubuntu 16.04的环境&#xff0c;里面暂时没有docker、ssh远程、vim等。 1. 更换国内源 直接输入docker 这里没有安装&#xff0c;那安装下 sudo apt install docker.io 开始安装 因为我没有修改源&#xff0c;所以这个速…

数据的表示和存储1

目录 数制和编码 信息的二进制编码 数值数据的表示 进制计数制 定点数和浮点数 定点数的编码表示 原码表示 补码表示 求特殊数的补码 求真值的补码 求补码的真值 移码表示Excess (biased) notiion C语言中的整数 无符号整数(unsigned integer) 带符号整数&#xff0…

QT sql查询模型,视图显示

SQL模型定义定义sql查询模型查询设置格式创建视图并显示setHeaderData() 函数定义 SQL 查询模型&#xff08;QSqlQueryModel&#xff09;是 Qt 提供的一种数据模型&#xff0c;用于执行 SQL 查询并返回结果集。它继承自 QSqlTableModel 类&#xff0c;可以使用 QSqlQuery 对象执…

【eXtplorer】本地搭建免费在线文件管理器并实现在外远程登录

文章目录1. 前言2. eXtplorer网站搭建2.1 eXtplorer下载和安装2.2 eXtplorer网页测试2.3 cpolar的安装和注册3.本地网页发布3.1.Cpolar云端设置3.2.Cpolar本地设置4.公网访问测试5.结语1. 前言 通过互联网传输文件&#xff0c;是互联网最重要的应用之一&#xff0c;无论是网上…

springboot学习2

一、spring boot自动装配原理 pom.xml spring-boot-dependencies 核心依赖在父工程中 在写或者引入一些spring boot依赖的时候&#xff0c;不需要指定版本&#xff0c;因为有这些版本仓库启动器 <dependency><groupId>org.springframework.boot</groupId>&…

使用golang实现日志收集系统的logagent

整体架构 参考 七米老师的日志收集项目 主要用go实现logagent的部分&#xff0c;logagent的作用主要是实时监控日志追加的变化&#xff0c;并将变化发送到kafka中。 之前我们已经实现了 用go连接kafka并向其中发送数据&#xff0c;也实现了使用tail库监控日志追加操作。 我们…

【Java基础】反射详述简单模拟SpringMVC

&#x1f6a9; 本文已收录至专栏&#xff1a;JAVA基础 &#x1f44d;希望能对你有所帮助 一.概述 反射是指对于任何一个Class类&#xff0c;在运行的时候都可以直接得到这个类全部成分&#xff0c;使得我们可以动态操作Java代码&#xff0c;同时反射也破坏了Java的封装性。 例…

如何清理电脑缓存,分享4个简单方法!

案例&#xff1a;如何清理电脑缓存 【朋友们&#xff01;我感觉我电脑的内存已经严重不足了&#xff0c;想清理下电脑的缓存释放空间&#xff0c;却不知如何清理&#xff0c;大家有什么好的方法吗&#xff1f;】 经常使用电脑的朋友可能都会发现&#xff0c;好像我们没下载什…

平台和编译器决定 char 是 signed char 或者 unsigned char

平台和编译器决定 char 是 signed char 或者 unsigned charThe C and C standards allows the character type char to be signed or unsigned, depending on the platform and compiler. Most systems, including x86 GNU/Linux and Microsoft Windows, use signed char, but …