You need to enable JavaScript to run this app. React中是否可以实现用于检测元素动画状态的useIsAnimating Hook?
优惠活动
大模型
产品
解决方案
定价
更多

React中是否可以实现用于检测元素动画状态的useIsAnimating Hook?

原实现的核心失效原因
  • 事件回调传参错误:代码中addEventListener('animationstart', setIsAnimating(true)) 会在effect执行时立刻调用setIsAnimating(true),将该调用的返回值(undefined)作为事件处理器传入,动画实际触发时根本不会执行状态更新逻辑。
  • 事件解绑完全失效:removeEventListener要求传入与绑定时完全一致的函数引用,解绑逻辑中传入的是重新构造的setState调用结果,与当初绑定的空引用不匹配,既无法正确清理监听、造成内存泄漏,也无法在组件卸载时移除副作用。
  • 场景覆盖不全:仅绑定了animationstart和animationend事件,完全没有覆盖CSS过渡(transition)的状态监测,同时遗漏了动画中途取消、重复迭代的边界场景,遇到无限循环动画、多动画并行、动画中途中断的情况时状态判断会完全失真。
  • ref绑定时机漏洞:如果effect执行时ref指向的DOM节点还未完成挂载,会直接跳过监听绑定,后续DOM挂载完成后也不会补绑监听逻辑。
修正后的可运行实现
function useIsAnimating(ref) {
  const [isAnimating, setIsAnimating] = React.useState(false);

  React.useEffect(() => {
    const targetEl = ref?.current;
    if (!targetEl) return;

    // 重算当前元素的动画运行状态
    const checkAnimationState = () => {
      // 获取当前元素上所有处于运行状态的动画,覆盖CSS动画、CSS过渡类型
      const runningAnimations = targetEl.getAnimations({ subtree: false });
      setIsAnimating(runningAnimations.length > 0);
    };

    // 绑定所有与动画、过渡状态变化相关的事件
    const trackEvents = [
      'animationstart', 'animationend', 'animationcancel', 'animationiteration',
      'transitionstart', 'transitionend', 'transitioncancel'
    ];
    trackEvents.forEach(eventName => {
      targetEl.addEventListener(eventName, checkAnimationState);
    });

    // 初始化时做一次状态校验
    checkAnimationState();

    // 用与绑定时完全相同的函数引用解绑监听
    return () => {
      trackEvents.forEach(eventName => {
        targetEl.removeEventListener(eventName, checkAnimationState);
      });
    };
  }, [ref]);

  return isAnimating;
}
关键实现逻辑说明
  • 所有状态变化事件统一复用同一份检测函数,保证绑定时和解绑时的函数引用完全一致,清理逻辑正常生效
  • 借助原生Element.getAnimations() 接口完成状态校验,自动覆盖CSS关键帧动画、CSS过渡、Web Animation API创建的所有运行中动画,不需要手动维护计数器处理多动画并行的场景
  • 每次事件触发时重新校验当前元素的所有运行中动画数量,只要存在至少一个未结束的动画,就将状态标记为true,从根源上避免单个动画结束就错误重置状态的问题
  • 移除了effect依赖中多余的setIsAnimating项,该API是React提供的稳定引用,不需要纳入依赖数组,不会触发不必要的副作用重跑
适配的场景范围
  • 无限循环的CSS关键帧动画会被正确识别为持续运行状态,不会因为缺少animationend事件导致状态卡死
  • 同时在元素上并行运行多个动画、过渡的场景,状态判断与实际运行情况保持一致
  • 动画被样式变更、用户交互、组件卸载中途打断的场景,会通过animationcancel/transitioncancel事件触发状态重算,不会出现状态与实际脱节的问题

内容的提问来源于stack exchange,提问作者Paul DeVito

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.10 08:06:08