You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React父组件状态变化触发SectionHeader子组件重复动画如何解决?

问题原因

  1. 每次状态变更触发头部动画:你在渲染字母span时使用nanoid()作为key,每次组件重渲染都会生成全新的key,React会销毁原有span节点、重新创建新节点,新节点自然会重新触发动画。同时你自定义的useIntersection Hook缺少清理逻辑,也可能导致重复监听的问题。
  2. 括号伪元素无动画:你的CSS仅为.letter类定义了可视状态下的动画规则,没有给伪元素::before、::after添加可视状态对应的动画触发逻辑。

修复方案

1. 修复动画重复触发问题

调整SectionHeader组件

  • 替换不稳定的nanoid() key为数组索引(头部文本固定,索引是稳定值)
  • 用React.memo包裹组件避免不必要重渲染
// 调整后的SectionHeader
const SectionHeader = React.memo(({ children }) => {
  const headerRef = useIntersection(
    styles.sectionHeader__isVisible,
    { rootMargin: '0px 0px -100px 0px', threshold: 1 },
    [children]
  );
  const textToLetters = children.split('').map((letter, idx) => {
    const style = !letter ? styles.space : styles.letter;
    return (
      <span className={style} key={idx}>
        {letter}
      </span>
    );
  });
  return (
    <div className={styles.sectionHeader_wrapper} ref={headerRef}>
      <h2 className={styles.sectionHeader}>{textToLetters}</h2>
    </div>
  );
});

完善useIntersection Hook

  • 添加observer清理逻辑,避免内存泄漏和重复监听
  • 补全useEffect依赖项,避免闭包问题
const useIntersection = (
  activeClass,
  { root = null, rootMargin = '0px', threshold = 1 },
  dependency = [],
  unobserveAfterFirstIntersection = true
) => {
  const elementRef = useRef(null);
  useEffect(() => {
    const options = { root, rootMargin, threshold };
    const observer = new IntersectionObserver((entries, observerObj) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
          entry.target.classList.add(activeClass);
          unobserveAfterFirstIntersection && observerObj.unobserve(entry.target);
        } else if (!unobserveAfterFirstIntersection) {
          entry.target.classList.remove(activeClass);
        }
      });
    }, options);
    const currentEl = elementRef.current;
    currentEl && observer.observe(currentEl);
    // 新增清理逻辑
    return () => {
      currentEl && observer.unobserve(currentEl);
      observer.disconnect();
    };
  // 补全所有依赖项
  }, [activeClass, root, rootMargin, threshold, unobserveAfterFirstIntersection, ...dependency]);
  return elementRef;
};

2. 修复伪元素无动画问题

在CSS中为可视状态下的伪元素添加动画规则,示例如下:

/* 新增伪元素动画触发规则 */
.sectionHeader__isVisible::before {
  animation: bracketLeftIn .3s ease-out forwards;
}
.sectionHeader__isVisible::after {
  animation: bracketRightIn .3s ease-out forwards .15s;
}

/* 自定义伪元素动画,可根据实际需求调整参数 */
@keyframes bracketLeftIn {
  from {
    opacity: 0;
    transform: translateX(-15px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}
@keyframes bracketRightIn {
  from {
    opacity: 0;
    transform: translateX(15px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

内容的提问来源于stack exchange,提问作者ann.piv

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 08:15:05