InView组件回调触发时AnimatedText动画重置问题排查
排查思路与解决方案
1. 核心问题:组件重复挂载导致动画重置
你的AnimatedText组件中,ComposeTag和ComposeMotion是在组件函数内部定义的:
const ComposeTag = ({ children }: ComposeTagProps) => { return React.createElement(as, { className, id }, children); }; const ComposeMotion = motion(ComposeTag);
每次AnimatedText重渲染时,这两个都会被重新创建,React会判定这是全新的组件类型,进而卸载旧实例、挂载新实例——这直接导致motion.span的动画状态被重置回initial配置。
解决方法:将组件定义移到外部或用useMemo缓存:
// 移到AnimatedText组件外部 const ComposeTag = React.memo(({ as, className, id, children }: ComposeTagProps & {as: TextElements, className?: string, id?: string}) => { return React.createElement(as, { className, id }, children); }); export const AnimatedText = ({ as = 'h1', className, children, auto = true, id, }: AnimatedTextProps) => { const textArr = children.split(' '); // 缓存motion包装后的组件,避免重复创建 const ComposeMotion = useMemo(() => motion(ComposeTag), []); // ... 其余代码不变 };
2. 优化不必要的重渲染
父组件Home中darkNavbar状态更新时,会触发整个组件重渲染,连带所有子组件(包括AnimatedText)也重渲染,会放大上述挂载问题。
优化点:
- 给
AnimatedText添加React.memo,避免props未变化时的无意义重渲染:export const AnimatedText = React.memo(({ as = 'h1', className, children, auto = true, id, }: AnimatedTextProps) => { // ... 组件内部代码 }); - 检查
Navbar是否依赖darkNavbar状态,如果是,确保Navbar的重渲染不会向上扩散(比如用context时限制更新范围)。
3. 验证组件挂载状态
可以在AnimatedText中添加日志,确认组件是重渲染还是卸载再挂载:
useEffect(() => { console.log('AnimatedText 挂载'); return () => console.log('AnimatedText 卸载'); }, []);
如果每次darkNavbar变化时都打印卸载/挂载日志,说明就是组件重复挂载导致的问题,回到第1点的解决方案即可。
4. 确认framer-motion动画逻辑
AnimatedText中同时使用了useAnimate和motion.span的initial属性,正常情况下framer-motion会保留组件重渲染时的动画状态,但如果组件被卸载再挂载,就会重置到初始状态。
另外,注意auto=false的AnimatedText(比如hero区域的文本),要确保它的动画是通过useMotionTimeline控制,不会被useInView的逻辑干扰。
内容的提问来源于stack exchange,提问作者ElliotSaha
相关产品推荐
相关产品推荐

