
react-use 的 useTween基于 requestAnimationFrame 的 0~1 数值补间动画 Hook 完全指南【免费下载链接】react-useReact Hooks — 项目地址: https://gitcode.com/gh_mirrors/re/react-useuseTween是 react-use 提供的 React 动画 Hook用于在指定时间内将一个数值从 0 平滑过渡补间/tween到 1适用于加载进度、颜色渐变、位移缩放、透明度过渡等一切需要数值随时间变化的动画场景。本文将结合仓库源码与测试完整讲解其参数含义、默认值、底层实现原理、错误处理与实战用法帮助你用几行代码就能在 React 组件中驱动流畅的动画。核心概念什么是数值补间Tween补间tween即 in-between是动画领域的基础技术给定起始值0、结束值1、持续时间ms与缓动函数easing系统按时间进度计算每一帧的中间值。useTween把这一过程封装成 React Hook——你拿到的返回值会随每一帧重渲染而递增最终在动画结束时稳定在 1可以直接喂给transform、opacity、width等任意 CSS 属性实现声明式的动画驱动。基础用法按照 useTween 文档 的定义最简单的调用不需要任何参数import {useTween} from react-use; const Demo () { const t useTween(); return ( div Tween: {t} /div ); };组件挂载后t会从 0 开始默认在 200ms 内约每帧重渲染一次逐步增长到 1。仓库中的 Storybook 演示 正是这样做的const t useTween()后直接渲染divTween: {t}/div你可以在浏览器中直观看到数值从 0 快速递增到 1 的过程。更贴近实战的用法是把补间值应用到样式上例如透明度与位移动画import {useTween} from react-use; const FadeIn () { const t useTween(outQuad, 600); return ( div style{{ opacity: t, transform: translateY(${(1 - t) * 20}px), }} 淡入并上移的卡片 /div ); };参数详解easing、ms、delayuseTween的函数签名如下来自 useTween 文档 与 源码实现useTween(easing?: string, ms?: number, delay?: number): number返回值从 0 开始在动画结束时达到 1。三个可选参数的含义、默认值与类型如下参数类型默认值说明easingstringinCirc缓动函数名称必须是ts-easing库中存在的有效名称见下文缓动名称msnumber200动画持续毫秒数即组件保持持续重渲染补间推进的时间长度delaynumber0延迟多少毫秒后才开始启动动画对应地单元测试 验证了这两组调用行为useTween()等价于useTween(inCirc, 200, 0)useTween(outCirc, 500, 15)会以outCirc缓动、持续 500ms、延迟 15ms 启动。缓动名称easingeasing参数接收字符串名称由ts-easing库项目依赖声明见 package.json版本^0.2.0提供映射表。源码中是这样取用的const fn: Easing easing[easingName];若名称无效easing[easingName]取到的是undefineduseTween会在非生产环境下抛出错误日志详见下文错误处理。由于错误日志会拼接Object.keys(easing).join(, )运行时打印的错误信息中会列出当前依赖版本下全部有效名称这是排查最直接的途径。常用的名称包括inCirc默认、outCirc测试中使用过、inOutCirc、linear、inQuad、outQuad、inCubic、outCubic、inSine、outSine、inExpo、outExpo、inBack、outBack、inElastic、outElastic、inBounce、outBounce等经典缓动曲线。提示不同缓动名称决定动画加速/减速/回弹的节奏。例如inCirc先慢后快outCirc先快后慢inOutElastic带弹性回弹效果可按观感需求选用。源码级原理useTween → useRaf → requestAnimationFrameuseTween本身非常精简完整实现见 src/useTween.ts核心逻辑委托给了另一个 HookuseRafconst useTween (easingName: string inCirc, ms: number 200, delay: number 0): number { const fn: Easing easing[easingName]; const t useRaf(ms, delay); // ...非生产环境的有效性校验... return fn(t); };也就是说补间流程分两步useRaf(ms, delay)产出线性进度tt从 0 平滑增长到 1fn(t)施加缓动曲线把线性进度映射为带加速度/回弹的曲线值最终仍落在 0~1 区间。useRaf 的帧循环实现useRaf见 src/useRaf.ts是真正的发动机其实现要点const onFrame () { const time Math.min(1, (Date.now() - start) / ms); set(time); loop(); }; const onStart () { timerStop setTimeout(() { cancelAnimationFrame(raf); set(1); }, ms); start Date.now(); loop(); }; const timerDelay setTimeout(onStart, delay);延迟启动setTimeout(onStart, delay)实现delay参数——延迟结束后才开始记录起始时间并启动帧循环帧推进loop()通过requestAnimationFrame(onFrame)驱动每帧计算(Date.now() - start) / ms作为当前进度并用Math.min(1, ...)钳制上限避免超出 1精确收尾动画时长到达ms后setTimeout取消帧循环并强制set(1)保证结束值精确等于 1清理机制effect 的 cleanup 中依次clearTimeout(timerStop)、clearTimeout(timerDelay)、cancelAnimationFrame(raf)组件卸载或ms/delay变化时不会产生泄漏或重复循环布局阶段启动它基于useIsomorphicLayoutEffectsrc/useIsomorphicLayoutEffect.ts挂载 effect在服务端渲染SSR时退化为useEffect从而兼容同构环境。值得注意的是useRaf通过set(time)更新 state 触发组件重渲染这正是useTween返回值随帧变化的来源。如果不想让整个组件树因动画高频重渲染可参照 useRafState 的思路把逐帧 state 收敛到局部或在子组件中消费t。错误处理无效 easing 名称如果传入不存在的缓动名称useTween不会静默失败而是在非生产环境process.env.NODE_ENV ! production下执行console.error( useTween() expected easingName property to be a valid easing function name, like: Object.keys(easing).join(, ) . ); console.trace(); return 0;即打印包含全部有效名称的错误提示与调用栈并返回0避免因fn为undefined导致运行时异常。这一行为在 单元测试 中有明确覆盖——传入grijanderl时返回值恒为0且console.error与console.trace各被调用一次。注意生产构建下该校验分支会被裁剪依赖NODE_ENV条件无效名称将直接导致fn(t)抛错因此务必保证传入名称在有效列表内。测试验证行为契约一目了然useTween 的测试 通过jest.spyOn分别 mock 了useRaf与ts-easing的缓动函数精确验证了三个契约默认参数useTween()会以(200, 0)调用useRaf用inCirc处理其返回值自定义参数useTween(outCirc, 500, 15)以(500, 15)调用useRaf并应用outCirc非法输入无效 easing 名称返回0并输出错误日志。这组测试同时印证了参数透传——useTween不参与时间计算只负责参数校验与缓动映射的职责划分。实战组合驱动更复杂的动画由于返回值是普通的 0~1 数字useTween可以自由组合进其他逻辑。例如与useBooleansrc/useBoolean.ts配合实现可切换的展开/收起动画或结合useSpring、useRafLoop做更精细的动画编排。一个常见的完整模式import {useTween, useBoolean} from react-use; const Collapse ({children}) { const [open, {toggle}] useBoolean(false); const t useTween(inOutCubic, 300); return ( div button onClick{toggle}{open ? 收起 : 展开}/button div style{{ maxHeight: ${t * 200}px, opacity: t, overflow: hidden, transition: none, }} {children} /div /div ); };注意useTween在组件每次挂载时都会从 0 重新播放一次如需根据开关状态重置动画可以将开关值作为key传入子组件或自行结合状态控制播放时机。注意事项与最佳实践默认参数即开即用不传任何参数时动画为inCirc缓动、200ms、无延迟适合快速验证高频重渲染是设计使然动画期间组件每帧约 16.6ms重渲染一次注意把昂贵计算移出动画组件或使用useMemo结束值精确为 1useRaf在超时后强制set(1)因此补间终点确定可用于需要精确对账的逻辑如进度条走到 100%SSR 安全底层基于useIsomorphicLayoutEffect可在服务端渲染环境中安全使用名称拼写敏感easing为字符串精确匹配拼写错误时开发环境会得到明确的错误提示生产环境则会直接抛错。相关资源useTween 文档本 Hook 的官方说明useTween 源码参数校验与缓动映射的完整实现useRaf 源码基于 requestAnimationFrame 的帧循环与定时器管理useTween 单元测试默认参数、自定义参数与错误分支的行为契约useTween Storybook 演示可直接运行的交互示例src/index.tsuseTween在 react-use 中的统一导出入口【免费下载链接】react-useReact Hooks — 项目地址: https://gitcode.com/gh_mirrors/re/react-use创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考