framer-motion、react-spring、react-motion 和 react-transition-group 都是 React 生态中用于处理动画和过渡效果的库,但它们的实现原理和适用场景截然不同。framer-motion 主打声明式 API 和布局动画,适合大多数 UI 交互场景。react-spring 基于物理弹簧模型,适合需要精细控制物理效果的复杂交互。react-motion 是早期的物理动画库,目前已被归档不再维护。react-transition-group 是底层工具,主要用于管理 CSS 类的添加和移除,常作为其他库的依赖或用于简单的 CSS 过渡。
在 React 应用中实现流畅的动画效果,选择合适的库至关重要。framer-motion、react-spring、react-motion 和 react-transition-group 代表了不同的技术路线。本文将从核心模型、代码实现、维护状态三个维度进行深度对比,帮助你在架构决策中做出正确选择。
不同的库采用了不同的驱动方式来处理动画,这直接影响了代码的编写方式和性能表现。
framer-motion 采用声明式模型。
// framer-motion: 声明式动画
import { motion } from "framer-motion";
function Box() {
return <motion.div animate={{ x: 100, opacity: 1 }} />;
}
react-spring 采用物理弹簧模型。
// react-spring: 物理弹簧模型
import { useSpring, animated } from "@react-spring/web";
function Box() {
const props = useSpring({ x: 100, opacity: 1 });
return <animated.div style={props} />;
}
react-motion 采用早期的物理模型。
// react-motion: 早期物理模型 (遗留)
import { Motion, spring } from "react-motion";
function Box() {
return (
<Motion style={{ x: spring(100), opacity: spring(1) }}>
{({ x, opacity }) => <div style={{ transform: `translateX(${x}px)`, opacity }} />}
</Motion>
);
}
react-transition-group 采用 CSS 类切换模型。
// react-transition-group: CSS 类切换
import { CSSTransition } from "react-transition-group";
function Box({ in: show }) {
return (
<CSSTransition in={show} timeout={300} classNames="fade">
<div /> {/* 动画由 .fade-enter-active 等 CSS 类控制 */}
</CSSTransition>
);
}
当我们需要改变一个元素的样式(如透明度或位置)时,各库的实现方式差异明显。
framer-motion 最简洁,直接在组件属性中定义目标值。
// framer-motion
<motion.div animate={{ opacity: 0.5, scale: 1.2 }} />
react-spring 需要先将样式对象传递给 Hook,再应用到 animated 组件。
// react-spring
const props = useSpring({ opacity: 0.5, scale: 1.2 });
<animated.div style={props} />
react-motion 需要使用渲染 props 来获取中间值,代码嵌套较深。
// react-motion
<Motion style={{ opacity: spring(0.5) }}>
{({ opacity }) => <div style={{ opacity }} />}
</Motion>
react-transition-group 无法直接做值动画,必须依赖 CSS。
// react-transition-group
/* CSS: .fade-enter-active { opacity: 0.5; transition: opacity 300ms; } */
<CSSTransition in={true} timeout={300} classNames="fade">
<div />
</CSSTransition>
处理组件进入和离开 DOM 时的动画是常见需求,各库的处理机制不同。
framer-motion 使用 AnimatePresence 包裹卸载组件。
// framer-motion
import { AnimatePresence } from "framer-motion";
{show && (
<AnimatePresence>
<motion.div exit={{ opacity: 0 }} />
</AnimatePresence>
)}
react-spring 通常配合 useTransition Hook 处理列表或条件渲染。
// react-spring
import { useTransition } from "@react-spring/web";
const transitions = useTransition(show ? [1] : [], {
from: { opacity: 0 },
enter: { opacity: 1 },
leave: { opacity: 0 }
});
return transitions((style, item) => <animated.div style={style} />);
react-motion 需要手动管理状态,通常结合 TransitionMotion。
// react-motion
import { TransitionMotion } from "react-motion";
<TransitionMotion
styles={show ? [{ key: "item", style: { opacity: 1 } }] : []}
willEnter={() => ({ opacity: 0 })}
willLeave={() => ({ opacity: 0 })}
>
{interpolatedStyles => interpolatedStyles.map(({ style }) => <div style={style} />)}
</TransitionMotion>
react-transition-group 专为生命周期过渡设计,原生支持 in 属性。
timeout 以匹配 CSS 过渡时间。// react-transition-group
<CSSTransition in={show} timeout={300} classNames="fade" unmountOnExit>
<div />
</CSSTransition>
选择库时,维护状态是架构决策中的关键风险因素。
framer-motion 处于活跃维护状态。
react-spring 处于活跃维护状态。
react-motion 已正式归档(Archived)。
react-transition-group 处于维护模式。
| 特性 | framer-motion | react-spring | react-motion | react-transition-group |
|---|---|---|---|---|
| 动画模型 | 声明式 | 物理弹簧 | 物理弹簧 (遗留) | CSS 类切换 |
| API 风格 | 组件属性 | Hooks | 渲染 Props | 组件属性 |
| 布局动画 | ✅ 原生支持 | ❌ 需手动计算 | ❌ 需手动计算 | ❌ 不支持 |
| 手势支持 | ✅ 内置拖拽/点击 | ❌ 需配合其他库 | ❌ 无 | ❌ 无 |
| 维护状态 | 🟢 活跃 | 🟢 活跃 | 🔴 已归档 | 🟡 稳定维护 |
| 学习曲线 | 低 | 中 | 高 | 中 |
framer-motion 就像是开箱即用的动画工具箱 🧰 — 适合大多数需要快速交付、交互丰富的前端项目。它的声明式 API 能显著减少样板代码,且布局动画功能独一无二。
react-spring 就像是精密的物理引擎 ⚙️ — 适合需要高度定制物理效果或与其他状态管理深度集成的场景。如果你熟悉 Hooks 且需要细粒度控制,它是最佳选择。
react-motion 是历史遗留产物 🕸️ — 尽管它曾经很流行,但现在已不再安全。请避免在任何新代码中引入它,迁移现有项目也是明智之举。
react-transition-group 就像是底层的基础设施 🧱 — 适合简单的 CSS 过渡或作为库作者构建更高级动画组件的基石。对于普通应用开发,通常有更高效的选择。
核心结论:对于 90% 的现代 React 项目,framer-motion 是首选。只有在需要特定物理效果或极简 CSS 过渡时,才考虑 react-spring 或 react-transition-group。务必避开 react-motion。
如果你的项目需要快速实现复杂的 UI 动画、手势交互或布局动画,请选择 framer-motion。它的声明式 API 学习成本低,且内置了性能优化,适合大多数生产环境的前端应用。
请不要在新项目中选择 react-motion。该库已正式归档且不再维护,缺乏对现代 React 特性(如 Hooks)的支持,存在潜在的安全和兼容性风险。
如果你需要基于物理原理的自然动画效果,或者需要通过 Hooks 对动画值进行细粒度的程序化控制,请选择 react-spring。它适合对动画曲线和物理参数有严格要求的场景。
如果你只需要简单的 CSS 类切换过渡,或者正在开发一个需要极低依赖的底层组件库,请选择 react-transition-group。它不提供值动画,但能很好地管理组件的生命周期状态。
npm install motion
Motion is available for React, JavaScript and Vue.
import { motion } from "motion/react"
function Component() {
return <motion.div animate={{ x: 100 }} />
}
Get started with Motion for React.
Note: Framer Motion is now Motion. Import from motion/react instead of framer-motion.
import { animate } from "motion"
animate("#box", { x: 100 })
Get started with JavaScript.
<script>
import { motion } from "motion-v"
</script>
<template> <motion.div :animate={{ x: 100 }} /> </template>
Get started with Motion for Vue.
Browse 330+ official examples, with copy-paste code that'll level-up your animations whether you're a beginner or an expert.
Over 100 examples come with a full step-by-step tutorial.
A one-time payment, lifetime-updates membership:
Motion is sustainable thanks to the kind support of its sponsors.
Motion powers the animations for all websites built with Framer, the web builder for creative pros. The Motion website itself is built on Framer, for its delightful canvas-based editing and powerful CMS features.
Motion drives the animations on the Cursor homepage, and is working with Cursor to bring powerful AI workflows to the Motion examples and docs.