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

前言—

本文通过实现 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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Golang每日一练(leetDay0034) 二叉树专题(3)

目录 100. 相同的树 Same Tree &#x1f31f; 101. 对称二叉树 Symmetric Tree &#x1f31f; 102. 二叉树的层序遍历 Binary Tree Level-order Traversal &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一…

程序设计方法学

体育竞技分析 问题分析 体育竞技分析 需求&#xff1a;毫厘是多少&#xff1f; 如何科学分析体育竞技比赛&#xff1f; 输入&#xff1a;球员的水平 输出&#xff1a;可预测的比赛成绩 体育竞技分析&#xff1a;模拟N场比赛 计算思维&#xff1a;抽象 自动化 模拟&am…

【算法题】2583. 二叉树中的第 K 大层和

题目&#xff1a; 给你一棵二叉树的根节点 root 和一个正整数 k 。 树中的 层和 是指 同一层 上节点值的总和。 返回树中第 k 大的层和&#xff08;不一定不同&#xff09;。如果树少于 k 层&#xff0c;则返回 -1 。 注意&#xff0c;如果两个节点与根节点的距离相同&…

能够翻译文档的免费软件-免费翻译整个文档的软件

chatgpt怎么实现批量翻译 ChatGPT是一种基于人工智能技术的自然语言处理软件&#xff0c;可以实现快速、准确的批量翻译操作&#xff0c;同时也支持多种语言翻译。下面是 ChatGPT 的批量翻译操作流程&#xff1a; 步骤 1: 确定翻译语言和翻译文本 首先需要确定要翻译的原文本…

java学习之局部内部类

目录 一、内部类简介 二、内部类的分类 三、局部内部类 第一点 第二点 第三点 第四点 第五点 第六点 第七点 一、内部类简介 类的五大成员&#xff1a;属性、方法、构造器、代码块、内部类 package com.hspedu.innerclass;public class InnerClass01 {public static…

AOP与SpringBoot使用AOP实例

AOP&#xff1a;Aspect Oriented Programming&#xff08;面向切面编程、面向方面编程&#xff09;&#xff0c;其实就是面向特定方法编程。 动态代理是面向切面编程最主流的实现。而SpringAOP是Spring框架的高级技术&#xff0c;旨在管理bean对象的过程中&#xff0c;主要通过…

Windows使用Dockers+battery historian踩坑记

1、首先&#xff0c;需要翻墙。 2、然后安装Dockers&#xff0c;网上好多博客说安装Docker Toolbox&#xff0c;我亲测无效&#xff0c;卸载后安装Docker for Windows&#xff0c;安装完成后打开&#xff0c;会提示&#xff1a; Hardware assisted virtualization and data e…

Mybatis03学习笔记

目录 使用注解开发 设置事务自动提交 mybatis运行原理 注解CRUD lombok使用&#xff08;偷懒神器&#xff0c;大神都不建议使用&#xff09; 复杂查询环境&#xff08;多对一&#xff09; 复杂查询环境&#xff08;一对多&#xff09; 动态sql环境搭建 动态sql常用标签…

大数据实战 --- 淘宝用户行为

目录 开发环境 数据描述 功能需求 数据准备 数据清洗 用户行为分析 找出有价值的用户 开发环境 HadoopHiveSparkHBase 启动Hadoop&#xff1a;start-all.sh 启动zookeeper&#xff1a;zkServer.sh start 启动Hive&#xff1a; nohup hiveserver2 1>/dev/null 2>…

生成树端口选举

所有交换机运行RSTP,SW1优先级4096,SW2优先级4096,SW3优先级8192,SW1的G0/0/1、G0/0/2接口通过手动模式加入Eth-Trunk 1,SW1的G0/0/3、G0/0/4接口通过手动模式加入Eth-Trunk 2,SW2的G0/0/1、G0/0/2接口通过手动模式加入Eth-Trunk 1,SW3的G0/0/1、G0/0/2接口通过手动模式…

【Python】Python读写.xlsx文件(基本操作、空值补全等)

【Python】Python读写.xlsx文件&#xff08;Pandas&#xff09; 文章目录 【Python】Python读写.xlsx文件&#xff08;Pandas&#xff09;1. 介绍2. Pandas读写xlsx文件2.1 基本操作2.1.1 实现任务2.1.2 代码2.1.3 结果 2.2 进阶操作2.2.1 写操作2.2.2 查看数据表的基本信息2.2…

电脑有自带的录屏功能吗?电脑录屏如何录人脸

案例&#xff1a;所有电脑都有自带的录屏功能吗&#xff1f; “在网上了解到电脑有录屏功能&#xff0c;但是我在我的电脑上又找不到。想问问小伙伴们是所有的电脑都有自带的录屏功能吗&#xff1f;怎样才能找到电脑自带的录屏功能&#xff1f;” 在日常使用电脑时&#xff0…

Python 无监督学习实用指南:1~5

原文&#xff1a;Hands-on unsupervised learning with Python 协议&#xff1a;CC BY-NC-SA 4.0 译者&#xff1a;飞龙 本文来自【ApacheCN 深度学习 译文集】&#xff0c;采用译后编辑&#xff08;MTPE&#xff09;流程来尽可能提升效率。 不要担心自己的形象&#xff0c;只关…

封装通用el-form表单(2种方式)

1、序言 项目地址&#xff1a;git clone form-demo: 封装通用el-form 一个后台管理系统最常见的是表单&#xff0c;表单最常见的是输入框、下拉选择、日期选择、单选、复选框等等&#xff0c; 系统添加若干模块&#xff0c;就复制粘贴若干个el-form、el-form-item&#xff0c;有…

重学Java设计模式-行为型模式-责任链模式

重学Java设计模式-行为型模式-责任链模式 内容摘自&#xff1a;https://bugstack.cn/md/develop/design-pattern/2020-06-18-重学 Java 设计模式《实战责任链模式》.html#重学-java-设计模式-实战责任链模式「模拟618电商大促期间-项目上线流程多级负责人审批场景」 责任链模…

Shell 脚本编程

1. shell 概述 &#x1f95e; shell 是一个命令行解释器&#xff0c;它能接受应用程序、用户 的命令&#xff0c;然后调用操作系统内核。 ⭐ 还是一门 功能强大的编程语言&#xff0c;易编写、易调试、灵活性强。 2. shell入门 &#xff08;1&#xff09;脚本格式 &#x1f…

js中 = 等号赋值的问题,Js中对象的引用问题,深浅拷贝

js "" 赋值符号 在js中 “”对于基本数据类型是赋值符号&#xff0c;比较&#xff08; 或 &#xff09;的时候是值&#xff1b;对于引用数据类型-对象来说 是地址引用&#xff0c;比较的时候是比较的地址。 基本数据类型和引用数据类型的比较 let a 3; let b a;…

离散数学_九章:关系(1)

关系 9.1关系及其性质 1、二元关系 2、集合A上的关系 3、n元素集合 有多少个关系&#xff1f; 4、关系的性质 1. 自反 2. 对称 3. 反对称 4. 传递 5、关系的组合 关系的合成 关系的幂 9.1关系及其性质 1、二元关系 设A和B是集合&#xff0c;一个从 A 到 B 的二元关…

stm32当中GPIO输出知识点汇总(GPIO的八种模式及其原理)

一、GPIO工作模式. 1. 四种输入模式 GPIO_Mode_IN_FLOATING 浮空输入模式 GPIO_Mode_IPU 上拉输入模式 GPIO_Mode_IPD 下拉输入模式 GPIO_Mode_AIN 模拟输入模式 2. 四种输出模式 GPIO_Mode_Out_OD 开漏输出模式 GPIO_Mode_Out_PP 推挽输出模式 GPIO_Mod…

CentOS7-部署Tomcat并运行Jpress

1. 简述静态网页和动态网页的区别。 2. 简述 Webl.0 和 Web2.0 的区别。 3. 安装tomcat8&#xff0c;配置服务启动脚本&#xff0c;部署jpress应用。1、简述静态网页和动态网页的区别 静态网页&#xff1a; 请求响应信息&#xff0c;发给客户端进行处理&#xff0c;由浏览器进…