多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

useConditionalTimeout 深度解析:beautiful-react-hooks 中条件驱动的延时执行 Hook 实现指南

useConditionalTimeout 深度解析:beautiful-react-hooks 中条件驱动的延时执行 Hook 实现指南 前端开发工具【免费下载链接】beautiful-react-hooks A collection of beautiful and (hopefully) useful React hooks to speed-up your components and hooks development 项目地址https://gitcode.com/gh_mirrors/be/beautiful-react-hooks点击查看免费下载useConditionalTimeout是 beautiful-react-hooks 库中一个条件驱动的异步 Hook它接收回调函数、延时毫秒数和一个布尔条件仅在条件为true时才启动setTimeout延时执行回调并支持在组件卸载或条件变化时按选项自动清理计时器。本文基于库文档 useConditionalTimeout 与源码 src/useConditionalTimeout.ts 展开带你掌握它的完整参数签名、两个选项cancelOnUnmount/cancelOnConditionChange的实际行为以及回调在组件重渲染下仍能正确执行的底层原理读完即可在“确认某状态后才启动定时任务”“可取消的倒计时提示”等场景中直接落地。为什么需要条件化的 Timeout原生setTimeout在 React 函数组件中直接使用会面临几个典型问题组件重渲染后回调引用可能过期、组件卸载后定时器仍在运行导致对已卸载组件调用setState、以及无法从 UI 上感知或取消计时器状态。库文档明确列出了useConditionalTimeout解决的三个动机只在某个条件被确认后才启动 timeout保证提供的回调在组件重渲染的情况下依然能被正确执行在组件卸载时视选项而定或条件被改变时终止 timeout。它与同库的 useTimeout 的区别正在于“条件”useTimeout在挂载时立即开始计时见 src/useTimeout.ts 中useEffect里直接调用setTimeout而useConditionalTimeout在启动前多了condition的判断。安装与导入按照 安装文档$ npm i --save beautiful-react-hooks或使用 yarn$ yarn add beautiful-react-hooks文档特别提醒始终从库中按单模块导入避免引入不必要的 Hook 及其依赖import useConditionalTimeout from beautiful-react-hooks/useConditionalTimeout;这一导入方式由构建脚本 scripts/generate-exports.js 保障它为每个src/*.ts文件生成独立的./useConditionalTimeout导出映射含import、require与types三种入口因此该 Hook 的package.jsonexports 是逐文件暴露的。useConditionalTimeout本身不依赖 rxjs、react-router-dom、redux 等第三方库属于零 peer 依赖 Hook。基本用法条件为 true 才启动 2 秒延时以下示例完整继承自官方文档演示“点击按钮把条件置为true2 秒后显示内容”的最基础场景import { useState } from react; import { Button, Space, Typography } from antd; import useConditionalTimeout from beautiful-react-hooks/useConditionalTimeout; const ConditionalDelayedContentComponent () { const [condition, setCondition] useState(false); const [showContent, setShowContent] useState(false); useConditionalTimeout(() { setShowContent(true) }, 2000, condition); const Actions [ Button typeprimary onClick{() setCondition(true)} disabled{condition} loading{condition !showContent} {condition ? Timer started : Start the timer}hellip; /Button ] return ( DisplayDemo titleuseConditionalTimeout actions{Actions} Space directionvertical Typography.Paragraph Click on the following button to change the condition that triggers the 2 seconds timeout to true /Typography.Paragraph Typography.Paragraph After timeout is elapsed a content is displayed /Typography.Paragraph {showContent div style{{ fontSize: 3rem }}/div} /Space /DisplayDemo) }; ConditionalDelayedContentComponent /三个参数的含义参数类型说明fnTCallback extends GenericFunction条件满足后要延时执行的回调泛型约束来自 src/shared/types.ts 中的GenericFunction即任意函数签名millisecondsnumber延时时长毫秒源码中会做typeof milliseconds number校验非数字时不会启动计时器conditionboolean触发开关只有为true时才会创建setTimeout返回值isCleared 状态与 clear 方法Hook 返回一个二元组[isCleared, clear]第一个元素是超时是否已被清除的布尔状态第二个元素是用于手动取消计时的函数。取消操作会触发一次重渲染因为内部调用了setIsCleared(true)。官方文档给出的可取消 5 秒超时示例如下注意取消按钮只在“尚未清除且内容尚未显示”时才渲染import { useState } from react; import { Button, Typography } from antd; import useConditionalTimeout from beautiful-react-hooks/useConditionalTimeout; const ConditionalDelayedContentComponent () { const [condition, setCondition] useState(false); const [showContent, setShowContent] useState(false); const [isCleared, clearTimeoutRef] useConditionalTimeout(() { setShowContent(true) }, 5000, condition); const Actions [ Button typeprimary onClick{() setCondition(true)} disabled{condition}Start a 5 seconds timeout/Button ] return ( DisplayDemo titleuseConditionalTimeout actions{Actions} Typography.ParagraphContent will show after 5 second starting from the following button click/Typography.Paragraph {showContent div style{{ fontSize: 3rem }}/div} {!isCleared !showContent Button onClick{clearTimeoutRef}Cancel timeout/Button} {isCleared Typography.ParagraphCleared/Typography.Paragraph} /DisplayDemo ) }; ConditionalDelayedContentComponent /测试文件 test/useConditionalTimeout.spec.js 对这个契约做了两条验证返回值确实是[boolean, function]数组调用clear()后result.current[0]由false变为true且 spy 回调未被调用、重复调用clear()不会抛错对应源码中if (timeout.current)的空值保护。选项Options参数详解第四个参数是可选的options对象两个开关的默认值均为true可在 src/useConditionalTimeout.ts 的defaultOptions常量中确认const defaultOptions: UseConditionalTimeoutOptios { cancelOnUnmount: true, cancelOnConditionChange: true }cancelOnUnmount组件卸载时是否清除定时器默认true。置为false时即便组件被卸载已创建的setTimeout仍会继续跑完并执行回调——适用于“把延时操作交给全局状态或副作用”的场景。文档示例import { useState } from react; import { Button } from antd; import useConditionalTimeout from beautiful-react-hooks/useConditionalTimeout; const ConditionalDelayedContentComponent () { const [condition, setCondition] useState(false); const [showContent, setShowContent] useState(false); const options { cancelOnUnmount: false }; useConditionalTimeout(() { setShowContent(true) }, 5000, condition, options); return ( DisplayDemo titleuseConditionalTimeout Button typeprimary onClick{() setCondition(true)}Start a 5 seconds timeout/Button {showContent div style{{ fontSize: 3rem }}/div} /DisplayDemo) }; ConditionalDelayedContentComponent /测试用例 验证了该行为以{ cancelOnUnmount: false }调用后执行rerender(null)卸载组件延时到期后 spy 依然被调用。实现位于 src/useConditionalTimeout.ts一个空依赖数组的useEffect返回清理函数组件卸载时检查opts.cancelOnUnmount为true则执行clear()。cancelOnConditionChange条件变化时是否清除定时器默认true。当condition相对于上一次渲染发生变化且选项为true时Hook 会清除当前计时器。文档示例演示了两个useConditionalTimeout实例互相牵制的效果import { useState } from react; import { Button } from antd; import useConditionalTimeout from beautiful-react-hooks/useConditionalTimeout; const ConditionalDelayedContentComponent () { const [condition, setCondition] useState(false); const [showContent, setShowContent] useState(false); useConditionalTimeout(() { setShowContent(true) }, 5000, condition); useConditionalTimeout(() { setCondition(false) }, 2000, condition); return ( DisplayDemo titleuseConditionalTimeout Button typeprimary onClick{() setCondition(true)}Start a 5 seconds timeout/Button {showContent div style{{ fontSize: 3rem }}/div} /DisplayDemo) }; ConditionalDelayedContentComponent /点击按钮把condition置为true后5 秒实例开始计时2 秒实例也同时开始计时并在 2 秒后把condition改回false——此时 5 秒实例检测到条件变化按默认选项清除自己的定时器因此点击按钮不会触发任何最终动作。这是把cancelOnConditionChange当作“条件撤销即取消任务”的用法。这一机制依赖对上一帧条件值的追踪源码通过 usePreviousValue 拿到prevCondition在 src/useConditionalTimeout.ts 中比较condition ! prevCondition后调用clear()。值得注意的细节是判断条件为prevCondition condition ! prevCondition即只有上一帧条件为真时条件翻转才会触发清除——从源码结构看这意味着false - true的翻转首次启动不会被误清真正生效的是true - false这类撤销场景。源码剖析重渲染下回调为何仍然正确对照 src/useConditionalTimeout.ts 全文整个 Hook 的运转可以拆成五个部分回调引用缓存。callback useRef(fn)配合一个[fn]依赖的useEffect每次传入的fn变化且通过 isFunction 校验检查typeof function及constructor/call/apply存在时就更新callback.current。这样定时器到期时调用的是callback.current()而非闭包里可能过期的旧fn——这是“组件重渲染后回调依然可靠执行”这一卖点的直接来源。计时器创建。[condition, milliseconds]依赖的useEffect中仅当condition typeof milliseconds number时执行setTimeout(() callback.current(), milliseconds)定时器句柄存入timeoutref。因此条件为false时根本不产生定时器。条件翻转清除。如上节所述基于usePreviousValue的翻转检测 cancelOnConditionChange选项。卸载清除。空依赖useEffect的清理函数按cancelOnUnmount选项决定去留。状态回传。isCleared是一个useState布尔值clear()内部先判空timeout.current执行clearTimeout并setIsCleared(true)最终以as UseConditionalTimeoutReturn断言为元组返回。健壮性方面测试 还覆盖了两个边界options显式传null时 Hook 照常工作源码用{ ...defaultOptions, ...(options || {}) }做了空值兜底传入非法参数fn是数字、milliseconds是对象时不抛错返回isCleared false且clear()可安全调用。与useTimeout的实现对照src/useTimeout.ts可以看出两者共享同一套设计模式相同的isCleared状态、相同的clear判空逻辑、相同的回调 ref 缓存只是条件版把“是否启动”和“条件变化时是否取消”抽成了独立逻辑并额外引入usePreviousValue做翻转检测。适用场景与 API 类型定义适用场景文档 “When to use”需要在某个特定时长之后、且仅当某个特定条件被验证时才执行一个回调的场景。典型如用户确认某项状态后才开始延时提示、表单进入“提交中”后延时弹出结果、轮询前等待某个开关开启等。文档末尾给出的完整类型签名如下引自 useConditionalTimeout.md Types 一节与 src/useConditionalTimeout.ts 中的导出类型一致import { type GenericFunction } from ./shared/types; /** * An async-utility hook that accepts a callback function and a delay time (in milliseconds), then delays the * execution of the given function by the defined time from when the condition verifies. */ declare const useConditionalTimeout: TCallback extends GenericFunction(fn: TCallback, milliseconds: number, condition: boolean, options?: UseConditionalTimeoutOptios) UseConditionalTimeoutReturn; export interface UseConditionalTimeoutOptios { cancelOnUnmount?: boolean; cancelOnConditionChange?: boolean; } export type UseConditionalTimeoutReturn [boolean, () void]; export default useConditionalTimeout;使用提示milliseconds变化时会重新进入计时useEffect从源码结构看这会以新的setTimeout覆盖旧句柄因此延时参数应按“每次变化重置计时”来设计条件为false时不产生任何定时器反复渲染是安全的如需在 UI 中展示“已取消”状态直接使用返回值中的isCleared它由clear()驱动更新。赞分享前端开发工具【免费下载链接】beautiful-react-hooks A collection of beautiful and (hopefully) useful React hooks to speed-up your components and hooks development 项目地址https://gitcode.com/gh_mirrors/be/beautiful-react-hooks点击查看免费下载相关推荐Kedro Hooks 深入指南Hook 规范、实现与执行机制全解析Kedro Hooks 深入指南Hook 规范、实现与执行机制全解析 导读 Hooks钩子是 Kedro 提供的一种扩展机制允许你在 Kedro 执行时数据工程工作流自动化beautiful-react-hooks 使用指南模块化导入 React Hooks、完整 Hook 清单与源码级实现解析beautiful react hooks 使用指南模块化导入 React Hooks、完整 Hook 清单与源码级实现解析 本篇基于 beautiful r前端开发工具Ornith-1.0-9B-OptiQ-4bit高级技巧如何优化提示词提升AI响应质量Ornith 1.0 9B OptiQ 4bit高级技巧如何优化提示词提升AI响应质量 Ornith 1.0 9B OptiQ 4bit是一款基于Qwen3.上一篇终极指南ZyPlayer播放器支持的倍速选项详解下一篇Metallb版本发布检查清单发布前必须完成的任务创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表