react-gsap 与 react-transition-group 集成实战:列表增删动画的优雅实现
【免费下载链接】react-gsapReact components for GSAP项目地址: https://gitcode.com/gh_mirrors/re/react-gsap
react-gsap是一个将 GSAP 动画平台声明式封装为 React 组件的开源库,用<Tween>和<Timeline>两个组件即可为 React 元素添加专业级动画。本文将它和react-transition-group搭配,解决列表增删时最头疼的"退出动画"问题——新增项淡入很简单,难点在于 React 卸载 DOM 太快,退出动画根本来不及播。下面给出一套完整的集成思路与实操方法。
为什么 React 列表的退出动画这么难?
React 的数据驱动渲染机制决定了:一旦从数组里删掉一项,对应的 DOM 节点会被立即卸载。CSS 的 transition 或 JS 动画还没来得及播完,元素就已经从页面上消失了。
传统解法是用react-transition-group的TransitionGroup:它负责"接管"生命周期,在项被移除时先保留 DOM 并标记退出状态,等动画结束才真正卸载。但react-transition-group本身只提供 CSS class 切换能力,想做流畅的贝塞尔缓动、弹性回弹、位移缩放组合动画,还得自己写 CSS。
这正是引入react-gsap的价值所在。
两个库的分工:谁管生命周期,谁管动画
集成的核心思路是让两个库各司其职:
| 职责 | 负责方 | 说明 |
|---|---|---|
| 挂载/退出生命周期 | react-transition-group | TransitionGroup拦截卸载时机,保留 DOM 直到动画完成 |
| 动画编排与缓动 | react-gsap | <Tween>/<Timeline>驱动 opacity、x、scale 等属性 |
| 性能保障 | GSAP 内核 | 走transform/opacity合成层,不掉帧 |
在react-gsap中,Tween组件通过克隆 children 自动收集动画目标节点(见 Tween.tsx 里的render()实现),卸载时自动调用tween.kill()清理,天然适配 React 组件的生命周期。而Timeline组件(Timeline.tsx)支持把多个 Tween 按position排进同一条时间线,还能通过labels打标签跳转——这正是列表动画需要的"进场 → 停留 → 退场"多阶段编排能力。
快速上手:安装与最小列表动画
安装两个依赖即可:
npm install gsap react-gsap react-transition-groupreact-gsap从 v2 起只依赖gsap一个 peer dependency,可独立升级 GSAP 版本(见 package.json)。最小示例——新增一项时淡入上浮:
<Tween from={{ opacity: 0, y: 20 }} duration={0.4} ease="power2.out"> <div>{item.text}</div> </Tween>就这么几行,from描述起始状态,GSAP 自动补间到元素的当前样式。stagger属性还支持数组错峰入场,ease可写back.out(1.7)这类弹性缓动,这些细节在 Animation.tsx 的官方示例里都有现成套路(FadeIn、FadeInLeft等)。
优雅退出:TransitionGroup 与 Tween 的协作
退出动画的关键是"退出期间别卸载"。用TransitionGroup包一层列表容器,每项放进自己的CSSTransition或自定义Transition组件中:
<TransitionGroup> {items.map(item => ( <Transition key={item.id} timeout={400}> {state => ( <Tween from={{ opacity: 0, y: 20 }} to={{ opacity: state === 'exited' ? 0 : 1 }} duration={0.35} ease="power2.inOut" > <div>{item.text}</div> </Tween> )} </Transition> ))} </TransitionGroup>这里有个小技巧:借助Transition渲染函数回调返回的state(entering/entered/exiting),把"退出态"作为to目标传给Tween。react-gsap在to变化时会重新invalidate()并重启动画(这一机制在 Tween.tsx 的componentDidUpdate中实现),因此状态翻转即可反向播放,无需手动调用任何 GSAP API。
删除时TransitionGroup会保持 DOM,Tween把该项平滑淡出并上移;timeout到期后才真正卸载,列表高度随之平滑收缩。
进阶:用 Timeline 编排列表的整体节奏
当列表变化希望有"整体感"时,把单项动画升级为时间线编排。例如新增一项时:
<Timeline duration={0.5} labels={[{ label: 'in', position: 0 }]}> <Tween from={{ opacity: 0, x: -30 }} ease="power2.out" position="in" /> <Tween to={{ scaleY: 1.05 }} duration={0.15} position="in+=0.3" /> </Timeline>labels让多段动画可以按名字对齐位置,position="in+=0.3"表示在in标签后 0.3 秒追加——先滑入、再轻微"弹一下"确认,交互手感立刻专业起来。时间线级别的playState属性还能用 PlayState 枚举(pause、resume、reverse等)与外部状态联动,官方 playground 的 ManualControl.tsx 演示了用按钮和滑块完全手动驱动动画的技巧。
调优清单:让列表动画更顺手的 5 个建议
- 只动 transform 和 opacity——
x、y、scale、opacity走合成层,性能最佳;避免动画width、height。 - timeout 略大于动画时长——
Transition的timeout设为动画时长的 1.2 倍左右,防止动画被截断。 - 退出用
exiting而非依赖 CSS——退出目标由state计算,避免残留 class 与 GSAP 内联样式打架。 - 需要滚动触发时加
Reveal——Reveal.tsx 基于IntersectionObserver在元素进入视口时自动播放时间线,适合"列表滚动加载 + 逐条浮现"场景。 - 想精细控制时拿底层对象——
react-gsap暴露了对底层 GSAP 实例的访问(低层访问思路见 LowLevelAccess.mdx),必要时可直接getGSAP()拿到 tween 做seek、eventCallback。
小结
react-gsap让 GSAP 的工业级动画能力以声明式组件进入 React,react-transition-group则补齐了它不负责的退出生命周期。两者组合,列表增删动画既流畅又可控:新增项弹性入场,删除项平滑退场,整体节奏由Timeline统一编排。这套"生命周期交给 TransitionGroup、帧交给 GSAP"的分工模式,也适用于标签页切换、卡片拖放回位等更多 React 动画场景。
【免费下载链接】react-gsapReact components for GSAP项目地址: https://gitcode.com/gh_mirrors/re/react-gsap
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考