当前位置: 首页 > news >正文

一文搞懂如何在 React 中使用 防抖(Debounce)和 节流(Throttle)

在前端的日常开发中,经常会使用到两个函数防抖(Debounce)和节流(Throttle),防抖函数可以有效控制在一段时间内只执行最后一次请求,例如搜索框输入时,只在输入完成后才进行请求接口。而节流函数则是每隔一段时间就执行一次请求。

在 React 应用开发时,不同于普通的 js,而且通过 react hook 机制,可以更方便的实现这两个功能。

防抖函数(Debounce)

从上面的图中可以看出,使用了防抖函数后,无论我们中间点了多少次,也只会在延时结束时执行一次。

使用 js 简单实现防抖函数

function debounce(fn: any, wait: number) {let timer: anyreturn (...args: any) => {// @ts-ignoreconst context = thisif (timer) clearTimeout(timer)timer = setTimeout(() => {timer = nullfn.apply(context,args)}, wait)}
} 

防抖的原理比较简单,就是使用闭包保存住计时器 timer 和 传递的函数,然后每次进入时都把之前的 timer 清空掉,这样延时 wait 每次都会从新开始计算,以此来达到只在延时结束后执行一次的效果。

在 React Input 中使用防抖函数

假设有个需求,用户通过输入商品名来搜索商品,那么不可能每次用户输入时都去请求后台接口,最好的处理方式就是加上防抖功能,只在用户输入完成后请求一次,这样做可以避免多次无效的调用后台接口。

实现这个功能用传统的方法可以这样做:

// 防抖函数,间隔时间为 2 秒
const changeDebounce = useCallback(debounce(handleChange, 2000), [])// 搜索框,非受控组件
<Input onChange={(e) => changeDebounce(e)} style={{width: 150, marginRight: 20}}/> 

可以看出上面的方式比较适合非受控的组件,如果是受控组件,可以采用 React Hooks 机制来实现:

// 传递给 Input 组件的值
const [value, setValue] = useState('')// useEffect 钩子函数
useEffect(() => {const getData = setTimeout(() => {if (!value) returninfo('异步请求....')}, 2000)return () => clearTimeout(getData)
}, [value])// 搜索框,受控组件
<Input value={value} onChange={(e) => setValue(e.target.value)} style={{width: 150, marginRight: 20}}/> 

可以看出,使用 useEffect 钩子函数可以很方便的实现防抖功能,原因就在于依赖了 value 值的变化,每次 value 变化后 useEffect 钩子都会执行清除逻辑,也就是 return 返回的函数,重新执行,这样就保证了多次输入内容后,只有到了间隔时间才会执行一次的逻辑。

如果再抽象一点,我们可以把这段逻辑提取成一个自定义 hook:

const useDebounce = <V>(value: V, wait: number) => {const [debounceValue,setDebounceValue] = useState(value)useEffect(() => {const timer = setTimeout(() => setDebounceValue(value),wait)return () => clearTimeout(timer)},[value,wait])return debounceValue
} 

在自定义 hook 中,使用了另外一个 state 进行保存和更新状态,只有在间隔时间到了才会更新,然后将这个新的 state 返回出去,在页面上可以这样使用,直接依赖 返回出来的状态,这样每次这个状态改变时,就是间隔时间到了的时候,就可以进行异步请求了。

const debounceValue = useDebounce(value,2000)useEffect(() => {if (!debounceValue) returninfo('异步请求....')
},[debounceValue]) 

最终的效果如下:

节流函数(Throttle)

上面的图比较好看出来节流函数的应用场景,一般是在滚动屏幕等执行次数很密集的情况下使用,有点限流的意思。

使用 js 实现节流函数

function throttle(fn: any, wait: number) {let inThrottle = falsereturn (...args: any) => {// @ts-ignoreconst context = thisif (!inThrottle) {inThrottle = truefn.apply(context, args)setTimeout(() => {inThrottle = false}, wait)}}
} 

节流函数实现的方式就是通过变量来控制是否执行逻辑,这里使用了 inThrottle 这个 boolean 值来进行控制,如果时间没到就一直是 true 的状态,直到时间到了后开始执行逻辑。

下面通过个小例子演示一下没有使用节流函数时,拖动效果:

<div style={{width: 50, height: 50, backgroundColor: 'blue'}} draggable={true} onDrag={() => { info('被拖动了~~~') }}
/> 

可以看到,在不试用节流函数的情况下,刚一拖动,就执行了许多许多次,如果这是请求,肯定是能把接口都刷爆的,所以这种情况一定要使用节流函数来控制一下频率,下面是使用了节流函数的效果:

const changeThrottle = useCallback(throttle(() => {info('异步请求....')
}, 2000), [])<div style={{width: 50, height: 50, backgroundColor: 'blue'}} draggable={true}onDrag={changeThrottle}
/> 

加了节流函数后,无论怎样快速拖动,执行的逻辑也是按照间隔时间的频率进行执行的。

在 React 中使用节流函数

我们可以像上面的防抖函数一样,将节流函数也使用 React Hook 来实现:

const useThrottle = <V>(value: V, wait: number) =>{const [throttledValue, setThrottledValue] = useState<V>(value)const lastExecuted = useRef<number>(Date.now())useEffect(() => {if (Date.now() >= lastExecuted.current + wait) {lastExecuted.current = Date.now()setThrottledValue(value)} else {const timerId = setTimeout(() => {lastExecuted.current = Date.now()setThrottledValue(value)}, wait)return () => clearTimeout(timerId)}}, [value, wait])return throttledValue
} 

这里主要通过时间对比来控制是否更新 throttledValue,以达到节流的效果,在组件中可以这样使用:

const [value, setValue] = useState(0)
const throttledValue = useThrottle(value, 2000)useEffect(() => {if (value === 0) returninfo('throttle 异步请求....')
}, [throttledValue])const handleDrag = () => {setValue(prevState => prevState + 1)
}<div style={{width: 50, height: 50, backgroundColor: 'blue'}} draggable={true} onDrag={handleDrag}
/> 

最终的效果和直接使用 throttle 函数是一样的。

总结

在前端开发中,防抖和节流函数几乎是必备的技能,它们的实现原理都离不开 js 闭包的特性,而在 React 中通过使用自定义的 hook,可以达到一样的效果,有些场景下可能还更方便些,但总的来说本质还是那样。

## 最后 整理了75个JS高频面试题,并给出了答案和解析,基本上可以保证你能应付面试官关于JS的提问。 ![](https://img-blog.csdnimg.cn/856589141da54a1fafc99ea9e7b017fe.png#pic_center) ![](https://img-blog.csdnimg.cn/72699310cddb41aa99c5f4387dfbefdf.png#pic_center) ![](https://img-blog.csdnimg.cn/431073429e9340ceb3c3880c0066c179.png#pic_center) ![](https://img-blog.csdnimg.cn/3eeb2c5bec44424da347971f2cb7ffbf.png#pic_center) > **有需要的小伙伴,可以点击下方卡片领取,无偿分享**

相关文章:

一文搞懂如何在 React 中使用 防抖(Debounce)和 节流(Throttle)

在前端的日常开发中&#xff0c;经常会使用到两个函数防抖&#xff08;Debounce&#xff09;和节流&#xff08;Throttle&#xff09;&#xff0c;防抖函数可以有效控制在一段时间内只执行最后一次请求&#xff0c;例如搜索框输入时&#xff0c;只在输入完成后才进行请求接口。…...

Airbyte API

Airbyte API涵盖了Airbyte功能的方方面面&#xff0c;主要分类&#xff1a;Source_definition&#xff1a;来源定义&#xff0c;实现了来源的增删改查功能。Destination_definition&#xff1a;目标定义&#xff0c;实现了目标的增删改查功能。Workspace&#xff1a;工作区管理…...

vue项目使用Electron开发桌面应用

添加npm配置避免安装Electron错误 请确保您的 node 版本大于等于 18. cmd运行&#xff1a; npm config edit 该命令会打开npm的配置文件&#xff0c;请在空白处添加&#xff1a; electron_builder_binaries_mirrorhttps://npmmirror.com/mirrors/electron-builder-binaries/ e…...

std::chrono笔记

文章目录1. radio原型作用示例2. duration原型&#xff1a;作用示例3. time_point原型作用示例4. clockssystem_clock示例steady_clock示例high_resolution_clock先说感觉&#xff0c;这个库真恶心&#xff0c;刚接触感觉跟shi一样&#xff0c;特别是那个命名空间&#xff0c;太…...

接收arp请求并发送回应的实例

本文简单介绍了arp协议,用一个实例查看收到的ARP请求,并对该请求发出ARP回应,实例有完整的源代码,使用C语言在Linux下实现,代码中有详细的注释。 1. ARP协议 ARP(Address Resolution Protocol),地址解析协议;在局域网上通过IP地址获取物理地址MAC的协议,该协议工作在数…...

【高性能计算】TVM使用TE手动优化矩阵乘法算法解析与代码解读

引言 注&#xff1a;本文主要介绍、解释TVM的矩阵优化思想、代码&#xff0c;需要配合代码注释一起阅读。 矩阵乘法是计算密集型运算。为了获得良好的 CPU 性能&#xff0c;有两个重要的优化措施&#xff1a; 提高内存访问的高速缓存命中率。复杂的数值计算和热点内存&#x…...

消息中间件的概念

中间件(middleware)是基础软件的一大类&#xff0c;属于可复用的软件范畴。中间件在操作系统软件&#xff0c;网络和数据库之上&#xff0c;应用软件之下&#xff0c;总的作用是为处于自己上层的应用软件提供运行于开发的环境&#xff0c;帮助用户灵活、高效的开发和集成复杂的…...

窃密恶意软件Raccoon最新样本Stealer v2分析

Raccoon 是一个恶意软件家族&#xff0c;2019 年来一直在地下犯罪论坛中以恶意软件即服务的身份进行售卖。2022 年 7 月&#xff0c;该恶意软件家族发布了 C 语言编写的新版本 Raccoon Stealer v2&#xff0c;打破了以往使用 C 开发的传统。 Raccoon 是一个信息窃密恶意软件&a…...

足球俱乐部管理系统

技术&#xff1a;Java、JSP等摘要&#xff1a;网站是一种主要的渠道。人们通过互联网快速、准确的发布信息、获取信息。而足球俱乐部是足球职业化、专业化的一个标志&#xff0c;是足球运动员以足球谋生时&#xff0c;所被聘用的机构&#xff0c;应运时代发展&#xff0c;规模、…...

2023上半年数学建模竞赛汇总(比赛时间、难易程度、含金量、竞赛官网)

1、美国大学生数学建模竞赛等级&#xff1a;国家级是否可跨校&#xff1a;否竞赛开始时间&#xff1a;2月17日~2月21日综合难度&#xff1a;⭐⭐⭐⭐ 竞赛含金量&#xff1a;⭐⭐⭐⭐⭐竞赛官网&#xff1a;https://www.comap.com/2、MathorCup高校数学建模挑战赛---大数据竞赛…...

【python学习笔记】:PHP7 Null合并运算符

在PHP7&#xff0c;一个新的功能&#xff0c;空合并运算符(??)已被引入。它被用来代替三元运算并与 isset()函数功能结合一起使用。如果它存在并且它不是空的&#xff0c;空合并运算符返回它的第一个操作数;否则返回第二个操作数。 示例 <?php// fetch the value of $_…...

数据结构与算法——3.时间复杂度分析1(概述)

前面我们已经介绍了&#xff0c;研究算法的最终目的是如何花费更少的时间&#xff0c;如何占用更少的内存去完成相同的需求&#xff0c;并且也通过案例演示了不同算法之间时间耗费和空间耗费上的差异&#xff0c;但我们并不能将时间占用和空间占用量化。因此&#xff0c;接下来…...

FPGA学习之日常工作复位电路

最近一个多月没有写博客了&#xff0c;然后最近工作中也遇到一个复位信号的问题。问题是这样的&#xff0c;关于外部复位信号&#xff0c;之前我们的处理方式都是通过PLL产生的Lock信号作为内部的复位信号。但是由于换到A54上面没有IP核&#xff0c;所以只有不用PLL&#xff0c…...

【洛谷 P1177】【模板】快速排序 题解(快速排序+指针)

【模板】快速排序 题目描述 利用快速排序算法将读入的 NNN 个数从小到大排序后输出。 快速排序是信息学竞赛的必备算法之一。对于快速排序不是很了解的同学可以自行上网查询相关资料&#xff0c;掌握后独立完成。&#xff08;C 选手请不要试图使用 STL&#xff0c;虽然你可以…...

Pthon--自动化实用技巧篇--文件目录处理

为什么要讲这一篇&#xff0c;主要是因为这个在自动化测试框架或者脚本的编写的时候会用到&#xff0c;还是比较方便的。看上述两个函数。getcwd()、chdir()。使用 os.getcwd() 函数获得当前工作目录。使用 os.chdir()函数改变当前工作目录。所以在用chdir()函数的时候别忘记指…...

想招到实干派程序员?你需要这种面试法

技术招聘中最痛的点其实是不精准。技术面试官或CTO们常常会向我们吐槽&#xff1a; “我经常在想&#xff0c;能不能把我们项目中的代码打印出来&#xff0c;作为候选人的面试题的一部分&#xff1f;” “能不能把一个Bug带上环境&#xff0c;让候选人来试试怎么解决&#xf…...

cesium常见操作:鼠标点击获取对象

目录 一、viewer.scene.pick&#xff08;获取Cartesian2&#xff09; 二、 viewer.scene.pickPosition&#xff08;获取Cartesian3&#xff09; 三、viewer.scene.drillPick&#xff08;穿透拾取&#xff0c;获取所有对象&#xff09; 四、viewer.scene.globe.pick&#xf…...

【玩转c++】git的安装和使用以及可视化处理

本期主题&#xff1a;git的安装和使用&#xff08;windows环境&#xff09;博客主页&#xff1a;小峰同学分享小编的在Linux中学习到的知识和遇到的问题 小编的能力有限&#xff0c;出现错误希望大家不吝赐1.两个工具介绍第一个工具git&#xff0c;链接gitee或者github等代码托…...

第三阶段02-Mybatis框架

Mybatis框架 Mybatis框架是目前最流行的数据持久层框架, 使用Mybatis框架可以帮助程序员自动生成JDBC代码, 程序员只需要通过注解或xml配置文件提供需要执行的SQL语句,以及对象和表的映射关系, Mybatis框架会根据此映射关系和SQL自动生成出JDBC代码,从而提高开发效率 Mybatis框…...

基于超像素的多视觉特征图像分割算法研究

0.引言 背景&#xff1a; 经典聚类算法&#xff1a;Kmeans、FCM 现有问题&#xff1a; 1&#xff09;现有算法大都是基于单一的视觉特征而设计的&#xff0c;eg&#xff1a;基于颜色特征的分割。 2&#xff09;没有考虑像素周围的空间信息&#xff1b;分割结果&#xff1a;多噪…...

利用ngx_stream_return_module构建简易 TCP/UDP 响应网关

一、模块概述 ngx_stream_return_module 提供了一个极简的指令&#xff1a; return <value>;在收到客户端连接后&#xff0c;立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量&#xff08;如 $time_iso8601、$remote_addr 等&#xff09;&a…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

JS设计模式(4):观察者模式

JS设计模式(4):观察者模式 一、引入 在开发中&#xff0c;我们经常会遇到这样的场景&#xff1a;一个对象的状态变化需要自动通知其他对象&#xff0c;比如&#xff1a; 电商平台中&#xff0c;商品库存变化时需要通知所有订阅该商品的用户&#xff1b;新闻网站中&#xff0…...

PAN/FPN

import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...

Netty从入门到进阶(二)

二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架&#xff0c;用于…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

Windows安装Miniconda

一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...

怎么让Comfyui导出的图像不包含工作流信息,

为了数据安全&#xff0c;让Comfyui导出的图像不包含工作流信息&#xff0c;导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo&#xff08;推荐&#xff09;​​ 在 save_images 方法中&#xff0c;​​删除或注释掉所有与 metadata …...