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

React-Hooks怎样封装防抖和节流-面试真题

Debounce

debounce 原意消除抖动,对于事件触发频繁的场景,只有最后由程序控制的事件是有效的。

防抖函数,我们需要做的是在一件事触发的时候设置一个定时器使事件延迟发生,在定时器期间事件再次触发的话则清除重置定时器,直到定时器到时仍不被清除,事件才真正发生。

const debounce = (fun, delay) => {let timer;return (...params) => {if (timer) {clearTimeout(timer);}timer = setTimeout(() => {fun(...params);}, delay);};
};

如果事件发生使一个变量频繁变化,那么使用debounce可以降低修改次数。通过传入修改函数,获得一个新的修改函数来使用。

如果是class组件,新函数可以挂载到组件this上,但是函数式组件局部变量每次render都会创建,debounce失去作用,这时需要通过useRef来保存成员函数(下文throttle通过useRef保存函数),是不够便捷的,就有了将debounce做成一个hook的必要。

function useDebounceHook(value, delay) {const [debounceValue, setDebounceValue] = useState(value);useEffect(() => {let timer = setTimeout(() => setDebounceValue(value), delay);return () => clearTimeout(timer);}, [value, delay]);return debounceValue;
}

在函数式组件中,可以将目标变量通过useDebounceHook转化一次,只有在满足delay的延迟之后,才会触发,在delay期间的触发都会重置计时。

配合useEffect,在debounce value改变之后才会做出一些动作。下面的text这个state频繁变化,但是依赖的是debounceText,所以引发的useEffect回调函数却是在指定延迟之后才会触发。

const [text,setText]=useState('');
const debounceText = useDebounceHook(text, 2000);
useEffect(() => {// ...console.info("change", debounceText);
}, [debounceText]);function onChange(evt){setText(evt.target.value)
}

上面一个搜索框,输入完成1秒(指定延迟)后才触发搜索请求,已经达到了防抖的目的。


Throttle

throttle 原意节流阀,对于事件频繁触发的场景,采用的另一种降频策略,一个时间段内只能触发一次。

节流函数相对于防抖函数用在事件触发更为频繁的场景上,滑动事件,滚动事件,动画上。

看一下一个常规的节流函数 (ES6):

function throttleES6(fn, duration) {let flag = true;let funtimer;return function () {if (flag) {flag = false;setTimeout(() => {flag = true;}, duration);fn(...arguments);// fn.call(this, ...arguments);// fn.apply(this, arguments); // 运行时这里的 this 为 App组件,函数在 App Component 中运行} else {clearTimeout(funtimer);funtimer = setTimeout(() => {fn.apply(this, arguments);}, duration);}};
}

参考 前端进阶面试题详细解答

(使用...arguments和 call 方法调用展开参数及apply 传入argument的效果是一样的)

扩展:在ES6之前,没有箭头函数,需要手动保留闭包函数中的this和参数再传入定时器中的函数调用:

所以,常见的ES5版本的节流函数:

function throttleES5(fn, duration) {let flag = true;let funtimer;return function () {let context = this,args = arguments;if (flag) {flag = false;setTimeout(function () {flag = true;}, duration);fn.apply(context, args); // 暂存上一级函数的 this 和 arguments} else {clearTimeout(funtimer);funtimer = setTimeout(function () {fn.apply(context, args);}, duration);}};
}

如何将节流函数也做成一个自定义Hooks呢?上面的防抖的Hook其实是对一个变量进行防抖的,从一个不间断频繁变化的变量得到一个按照规则(停止变化delay时间后)才能变化的变量。我们对一个变量的变化进行节流控制,也就是从一个不间断频繁变化的变量指定duration期间只能变化一次(结束后也会变化)的变量

throttle对应的Hook实现:

(标志能否调用值变化的函数的flag变量在常规函数中通过闭包环境来保存,在Hook中通过useRef保存)

function useThrottleValue(value, duration) {const [throttleValue, setThrottleValue] = useState(value);let Local = useRef({ flag: true }).current;useEffect(() => {let timer;if (Local.flag) {Local.flag = false;setThrottleValue(value);setTimeout(() => (Local.flag = true), duration);} else {timer = setTimeout(() => setThrottleValue(value), duration);}return () => clearTimeout(timer);}, [value, duration, Local]);return throttleValue;
}

对应的在手势滑动中的使用:

export default function App() {const [yvalue, setYValue] = useState(0);const throttleValue = useThrottleValue(yvalue, 1000);useEffect(() => {console.info("change", throttleValue);}, [throttleValue]);function onMoving(event, tag) {const touchY = event.touches[0].pageY;setYValue(touchY);}return (<divonTouchMove={onMoving}style={{ width: 200, height: 200, backgroundColor: "#a00" }}    />);
}

这样以来,手势的yvalue值一直变化,但是因为使用的是throttleValue,引发的useEffect回调函数已经符合规则被节流,每秒只能执行一次,停止变化一秒后最后执行一次。

对值还是对函数控制

上面的Hooks封装其实对值进行控制的,第一个防抖的例子中,输入的text跟随输入的内容不断的更新state,但是因为useEffect是依赖的防抖之后的值,这个useEffect的执行是符合防抖之后的规则的。

可以将这个防抖规则提前吗? 提前到更新state就是符合防抖规则的,也就是只有指定延迟之后才能将新的value进行setState,当然是可行的。但是这里搜索框的例子并不好,对值变化之后发起的请求可以进行节流,但是因为搜索框需要实时呈现输入的内容,就需要实时的text值。

对手势触摸,滑动进行节流的例子就比较好了,可以通过设置duration来控制频率,给手势值的setState降频,每秒只能setState一次:

export default function App() {const [yvalue, setYValue] = useState(0);const Local = useRef({ newMoving: throttleFun(setYValue, 1000) }).current;useEffect(() => {console.info("change", yvalue);}, [yvalue]);function onMoving(event, tag) {const touchY = event.touches[0].pageY;Local.newMoving(touchY);}return (<divonTouchMove={onMoving}style={{ width: 200, height: 200, backgroundColor: "#a00" }}    />);
}//常规节流函数
function throttleFun(fn, duration) {let flag = true;let funtimer;return function () {if (flag) {flag = false;setTimeout(() => (flag = true), duration);fn(...arguments);} else {clearTimeout(funtimer);funtimer = setTimeout(() => fn.apply(this, arguments), duration);}};
}

这里就是对函数进行控制了,控制函数setYValue的频率,将setYValue函数传入节流函数,得到一个新函数,手势事件中使用新函数,那么setYValue的调用就符合了节流规则。如果这里依然是对手势值节流的话,其实会有很多的不必要的setYValue执行,这里对setYValue函数进行节流控制显然更好。

需要注意的是,得到的新函数需要通过useRef作为“实例变量”暂存,否则会因为函数组件每次render执行重新创建。

相关文章:

React-Hooks怎样封装防抖和节流-面试真题

Debounce debounce 原意消除抖动&#xff0c;对于事件触发频繁的场景&#xff0c;只有最后由程序控制的事件是有效的。 防抖函数&#xff0c;我们需要做的是在一件事触发的时候设置一个定时器使事件延迟发生&#xff0c;在定时器期间事件再次触发的话则清除重置定时器&#xff…...

算法训练营 day51 动态规划 打家劫舍系列

算法训练营 day51 动态规划 打家劫舍系列 打家劫舍 198. 打家劫舍 - 力扣&#xff08;LeetCode&#xff09; 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#…...

【蓝桥集训】第六天——递归

作者&#xff1a;指针不指南吗 专栏&#xff1a;Acwing 蓝桥集训每日一题 &#x1f43e;或许会很慢&#xff0c;但是不可以停下来&#x1f43e; 文章目录1.树的遍历2.递归求阶乘3.求斐波那契数列1.树的遍历 一个二叉树&#xff0c;树中每个节点的权值互不相同。 现在给出它的后…...

react源码中的hooks

今天&#xff0c;让我们一起深入探究 React Hook 的实现方法&#xff0c;以便更好的理解它。但是&#xff0c;它的各种神奇特性的不足是&#xff0c;一旦出现问题&#xff0c;调试非常困难&#xff0c;这是由于它的背后是由复杂的堆栈追踪&#xff08;stack trace&#xff09;支…...

038.Solidity入门——25调用其他合约的方法

Solidity 提供了几种方式用于调用其他合约&#xff1a;方法描述直接调用使用 address.call 函数&#xff0c;可以向另一个合约发送消息并返回结果。低级调用使用 address.call 或 address.callcode 函数&#xff0c;可以执行一个外部合约中的代码。与直接调用不同&#xff0c;低…...

Revit项目浏览器的标准设置应用和快速视图样板?

一、Revit项目浏览器的标准设置应用 设计院阶段的BIM应用&#xff0c;主要是Revit出施工图方面&#xff0c;需要涉及到很多标准的制定方面的问题&#xff0c;而且这个标准不仅仅是一个命名标准&#xff0c;还有很多的符合本院的出图标准等等&#xff0c;本期就不做详细讨论&…...

安装MQTT Server遇到报错“cannot verify mosquitto.org‘s certificate”,该如何解决?

MQTT是基于发布/订阅的轻量级即时通讯协议&#xff0c;很适合用于低带宽、不稳定的网络中进行远程传感器和控制设备通讯等操作中。在我们的软件研发中&#xff0c;也经常使用MQTT协议进行消息通信等。今天来和大家分享一些关于在安装MQTT Server中遇到的疑难问题及解决思路。当…...

程序员如何向架构师转型?看完就明白该怎么做了

软件行业技术开发从业人员众多&#xff0c;但具备若干年开发经验的普通的开发人员往往面临个人发展的瓶颈&#xff0c;即如何从普通开发人员转型成高层次的系统架构师和技术管理人员。想成为一名架构师&#xff0c;应当具备全面的知识体系&#xff0c;需要进行系统的学习和实践…...

Flask入门(9):蓝图

目录9.蓝图9.1 概述9.2 蓝图项目结构结构1结构29.3 添加前缀9.4 静态文件9.5 模板9.6 构建 URLs9.蓝图 参考&#xff1a;http://www.pythondoc.com/flask/blueprints.html 9.1 概述 Flask 使用了 蓝图 的概念在一个应用或者跨应用中构建应用组件以及支持通用模式。 蓝图很好…...

跑步戴哪种耳机好,最适合运动跑步的蓝牙耳机

经常跑步使用的耳机&#xff0c;还是要选择佩戴着舒适以及牢固的运动耳机最为合适&#xff0c;在运动当中会遇到耳机掉落或者长时间佩戴耳道感到难受的现象发生&#xff0c;那么什么蓝牙耳机是最适合运动当中佩戴呢&#xff1f;下面这些耳机分享希望能够帮助大家。 1、南卡Run…...

微信小程序实现瀑布流布局

微信小程序实现瀑布流布局1、简单实例&#xff0c;纯图片后台返回图片高度https://blog.csdn.net/qq_45967222/article/details/1190318762、纯图片后台返回图片高度、通过wx.getImageInfo获取在线图片高度、按照奇数偶数来显示https://blog.csdn.net/baidu_35290582/article/d…...

2023最新网络工程师HCIA-Datacom“1000”道题库,光速刷题拿证

HCIA认证是华为认证体系的初级认证&#xff0c;可以说是网工进入IT行业的一张从业资格证&#xff01; HCIA-Datacom考试覆盖数通基础知识 包括 TCP/IP 协议栈基础知识&#xff0c;OSPF 路由协议基本原理以及在华为路由器中的配置实现&#xff0c;以太网技术、生成树、VLAN 原…...

[蓝桥杯] 递归与递推习题训练

文章目录 一、递归实现指数型枚举 1、1 题目描述 1、2 题解关键思路与解答 二、递归实现排列型枚举 2、1 题目描述 2、2 题解关键思路与解答 三、递归实现组合型枚举 3、1 题目描述 3、2 题解关键思路与解答 四、带分数 4、1 题目描述 4、2 题解关键思路与解答 五、费解的开关…...

领航智能汽车信息安全新征程 | 云驰未来乔迁新址

2月20日&#xff0c;在北京朝阳百子湾东朝时代创意园&#xff0c;云驰未来迎来乔迁之喜&#xff0c;智能汽车和自动驾驶领域的行业领导、合作伙伴与客户、投资人及媒体嘉宾齐聚现场&#xff0c;共同见证云驰未来迈上新的发展征程。 作为中国智能网联汽车和自动驾驶信息安全行业…...

Kaldi语音识别技术(七) ----- 训练GMM

Kaldi语音识别技术(七) ----- GMM 文章目录Kaldi语音识别技术(七) ----- GMM训练GMMtrain_mono.sh 用于训练GMM训练GMM—生成文件训练GMM—final模型查看训练GMM—final.occs查看训练GMM—对齐信息查看训练GMM—fsts.*.gz查看训练GMM—tree决策树查看align_si.sh 用于对齐训练G…...

Java 集合基础

文章目录一、集合概念二、ArrayList1. 构造方法和添加方法2. 常用方法三、案例演示1. 存储字符串并遍历2. 存储学生对象并遍历3. 键盘录入学生对象并遍历一、集合概念 编程的时候如果要存储多个数据&#xff0c;使用长度固定的数组存储格式&#xff0c;不一定满足我们的需要&a…...

Day896.MySql的kill命令 -MySQL实战

MySql的kill命令 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于MySql的kill命令的内容。 在 MySQL 中有两个 kill 命令&#xff1a; 一个是 kill query 线程 id&#xff0c;表示终止这个线程中正在执行的语句&#xff1b;一个是 kill connection 线程 id&#…...

L2-010 排座位

布置宴席最微妙的事情&#xff0c;就是给前来参宴的各位宾客安排座位。无论如何&#xff0c;总不能把两个死对头排到同一张宴会桌旁&#xff01;这个艰巨任务现在就交给你&#xff0c;对任何一对客人&#xff0c;请编写程序告诉主人他们是否能被安排同席。 输入格式&#xff1…...

C++的完美讲解,还不快来看看?

目录 简介&#xff1a; 创建C程序&#xff1a; Windows编译简介&#xff1a; Hello,C World! 简介&#xff1a; C融合了3中不同的编程传统:C语言代表的过程性传统、C在C语言基础上添加的类代表的面向对象语言的传统以及C模板支持的通用编程传统。一般来说&#xff0c;计算机语言…...

C语言学习_DAY_5_循环结构while和for语句【C语言学习笔记】

高质量博主&#xff0c;点个关注不迷路&#x1f338;&#x1f338;&#x1f338;&#xff01; 目录 I. 案例引入 II. while语句 III. do while语句 IV. for语句 前言: 书接上回&#xff0c;判断结构已经解决&#xff0c;接下来是另一种很重要的结构&#xff1a;循环结构的实…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

《通信之道——从微积分到 5G》读书总结

第1章 绪 论 1.1 这是一本什么样的书 通信技术&#xff0c;说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号&#xff08;调制&#xff09; 把信息从信号中抽取出来&am…...

什么是EULA和DPA

文章目录 EULA&#xff08;End User License Agreement&#xff09;DPA&#xff08;Data Protection Agreement&#xff09;一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA&#xff08;End User License Agreement&#xff09; 定义&#xff1a; EULA即…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...

深入浅出Diffusion模型:从原理到实践的全方位教程

I. 引言&#xff1a;生成式AI的黎明 – Diffusion模型是什么&#xff1f; 近年来&#xff0c;生成式人工智能&#xff08;Generative AI&#xff09;领域取得了爆炸性的进展&#xff0c;模型能够根据简单的文本提示创作出逼真的图像、连贯的文本&#xff0c;乃至更多令人惊叹的…...

PH热榜 | 2025-06-08

1. Thiings 标语&#xff1a;一套超过1900个免费AI生成的3D图标集合 介绍&#xff1a;Thiings是一个不断扩展的免费AI生成3D图标库&#xff0c;目前已有超过1900个图标。你可以按照主题浏览&#xff0c;生成自己的图标&#xff0c;或者下载整个图标集。所有图标都可以在个人或…...

GB/T 43887-2024 核级柔性石墨板材检测

核级柔性石墨板材是指以可膨胀石墨为原料、未经改性和增强、用于核工业的核级柔性石墨板材。 GB/T 43887-2024核级柔性石墨板材检测检测指标&#xff1a; 测试项目 测试标准 外观 GB/T 43887 尺寸偏差 GB/T 43887 化学成分 GB/T 43887 密度偏差 GB/T 43887 拉伸强度…...

C/Python/Go示例 | Socket Programing与RPC

Socket Programming介绍 Computer networking这个领域围绕着两台电脑或者同一台电脑内的不同进程之间的数据传输和信息交流&#xff0c;会涉及到许多有意思的话题&#xff0c;诸如怎么确保对方能收到信息&#xff0c;怎么应对数据丢失、被污染或者顺序混乱&#xff0c;怎么提高…...