react-spring vs framer-motion vs lottie-react-native vs react-native-animatable vs react-native-reanimated vs react-transition-group
React 与 React Native 动画库的技术选型指南
react-springframer-motionlottie-react-nativereact-native-animatablereact-native-reanimatedreact-transition-group类似的npm包:

React 与 React Native 动画库的技术选型指南

framer-motionlottie-react-nativereact-native-animatablereact-native-reanimatedreact-springreact-transition-group 都是用于在 React 或 React Native 应用中实现动画效果的流行库,但它们的设计目标、性能特征和适用场景差异显著。framer-motionreact-spring 主要面向 Web 端,提供声明式、物理驱动的动画能力;react-transition-group 专注于基于状态变化的进入/离开过渡;而 react-native-reanimatedlottie-react-nativereact-native-animatable 则专为 React Native 设计,分别针对高性能原生动画、Lottie JSON 动画集成和简单内置动画封装。这些库在渲染线程、API 风格、性能开销和跨平台支持方面存在关键区别,开发者需根据项目平台、动画复杂度和性能要求进行权衡。

npm下载趋势

3 年

GitHub Stars 排名

统计详情

npm包名称
下载量
Stars
大小
Issues
发布时间
License
react-spring1,112,08529,0918.36 kB1388 个月前MIT
framer-motion031,9624.73 MB1212 个月前MIT
lottie-react-native017,146290 kB192 天前Apache-2.0
react-native-animatable09,94859.8 kB1693 年前MIT
react-native-reanimated010,8254.04 MB3519 天前MIT
react-transition-group010,246244 kB258-BSD-3-Clause

React 与 React Native 动画库深度技术对比

在现代前端开发中,动画不仅是视觉点缀,更是提升用户体验的关键手段。然而,面对 framer-motionlottie-react-nativereact-native-animatablereact-native-reanimatedreact-springreact-transition-group 这些主流动画库,开发者常陷入“选哪个”的困境。本文从真实工程视角出发,深入剖析它们的核心机制、适用边界与性能特征,助你做出精准技术决策。

🧩 核心定位与平台支持

首先明确一点:这些库并非完全可互换。它们分为 Web 专用React Native 专用跨平台 三类。

  • Web 专用framer-motionreact-spring(默认配置)、react-transition-group
  • React Native 专用lottie-react-nativereact-native-animatablereact-native-reanimated
  • 跨平台react-spring(通过 @react-spring/native 支持 RN)

⚠️ 注意:react-native-animatable 自 2019 年起已无实质性更新,官方仓库标记为“不再积极维护”,强烈不建议在新项目中使用

🖥️ Web 端动画:声明式 vs 物理模型 vs 状态过渡

基础进入/离开动画:react-transition-group

如果你只需要在组件挂载/卸载时添加简单过渡(如淡入淡出),react-transition-group 是最轻量的选择。它不处理复杂动画逻辑,而是帮你管理 CSS 类名切换。

// react-transition-group
import { CSSTransition } from 'react-transition-group';

function Fade({ in: inProp }) {
  return (
    <CSSTransition in={inProp} timeout={300} classNames="fade">
      <div>Hello</div>
    </CSSTransition>
  );
}

/* 对应 CSS */
.fade-enter { opacity: 0; }
.fade-enter-active { opacity: 1; transition: opacity 300ms; }

声明式高阶动画:framer-motion

framer-motion 以极简 API 实现复杂交互动画,尤其擅长布局动画和手势集成。

// framer-motion
import { motion } from 'framer-motion';

<motion.div
  animate={{ x: 100, rotate: 360 }}
  transition={{ type: 'spring', stiffness: 300 }}
/>

// 布局动画示例
<motion.div layout>
  {isOpen && <motion.div layoutId="panel">Content</motion.div>}
</motion.div>

物理驱动动画:react-spring

react-spring 基于弹簧物理模型,适合需要自然弹性效果的场景(如拖拽回弹、数据可视化)。

// react-spring
import { useSpring, animated } from 'react-spring';

function SpringBox() {
  const props = useSpring({ x: 100, rotate: 360 });
  return <animated.div style={props} />;
}

// 手势集成
const [{ x, y }, api] = useSpring(() => ({ x: 0, y: 0 }));
const bind = useDrag(({ offset: [x, y] }) => api.start({ x, y }));
return <animated.div {...bind()} style={{ x, y }} />;

📱 React Native 动画:性能是核心分水岭

高性能原生动画:react-native-reanimated

react-native-reanimated 的核心优势在于将动画逻辑移至 UI 线程执行,彻底规避 JavaScript 线程卡顿。其 API 分为 v1(回调式)和 v2(工作lets),v2 更推荐。

// react-native-reanimated (v2)
import Animated, { useSharedValue, useAnimatedStyle, withSpring } from 'react-native-reanimated';

function ReanimatedBox() {
  const offset = useSharedValue(0);
  const animatedStyle = useAnimatedStyle(() => {
    return { transform: [{ translateX: offset.value }] };
  });

  const onPress = () => {
    offset.value = withSpring(100);
  };

  return <Animated.View style={animated_style} onTouchEnd={onPress} />;
}

Lottie 动画播放器:lottie-react-native

该库仅用于渲染设计师导出的 Lottie JSON 文件,不提供程序化动画能力。

// lottie-react-native
import LottieView from 'lottie-react-native';

<LottieView
  source={require('./animation.json')}
  autoPlay
  loop
/>

已过时的简易方案:react-native-animatable

所有动画在 JS 线程运行,性能较差,仅作历史参考。

// react-native-animatable (不推荐)
import Animatable from 'react-native-animatable';

<Animatable.View animation="fadeIn" duration={500} />

⚡ 性能与线程模型对比

渲染线程性能瓶颈适用场景
framer-motionWeb 主线程复杂布局重排Web UI 交互动画
react-springWeb 主线程高频更新计算物理模拟、数据可视化
react-transition-groupWeb 主线程极低(仅类名切换)简单进入/离开过渡
react-native-reanimatedUI 线程几乎无RN 高性能交互动画
lottie-react-native原生渲染线程Lottie 文件复杂度播放预设矢量动画
react-native-animatableJS 线程明显卡顿避免使用

🛠️ 何时选择哪个库?实战场景分析

场景 1:Web 应用中的路由切换动画

  • 需求:页面切换时平滑过渡,支持共享元素(如图片放大)
  • 推荐framer-motion
  • 原因:内置 AnimatePresencelayoutId 完美解决此问题
// framer-motion 路由动画
import { AnimatePresence, motion } from 'framer-motion';

<AnimatePresence mode="wait">
  <motion.div
    key={location.pathname}
    initial={{ opacity: 0 }}
    animate={{ opacity: 1 }}
    exit={{ opacity: 0 }}
  >
    {children}
  </motion.div>
</AnimatePresence>

场景 2:React Native 中的可拖拽抽屉

  • 需求:用户可拖拽面板,松手后自动吸附到最近位置
  • 推荐react-native-reanimated + react-native-gesture-handler
  • 原因:必须 UI 线程执行以保证 60fps 流畅度
// reanimated 拖拽示例(简化)
const dragX = useSharedValue(0);
const gestureHandler = useAnimatedGestureHandler({
  onActive: (event) => { dragX.value = event.translationX; },
  onEnd: () => { dragX.value = withSpring(0); }
});
const style = useAnimatedStyle(() => ({ transform: [{ translateX: dragX.value }] }));

return <PanGestureHandler onGestureEvent={gestureHandler}>
  <Animated.View style={style} />
</PanGestureHandler>;

场景 3:跨平台的数据仪表盘

  • 需求:数字变化带动画(如 0 → 1000),需在 Web 和 RN 一致表现
  • 推荐react-spring
  • 原因@react-spring/web@react-spring/native 提供统一 API
// react-spring 跨平台数字动画
import { useSpring, animated } from '@react-spring/web'; // Web
// import { useSpring, animated } from '@react-spring/native'; // RN

function NumberDisplay({ value }) {
  const { number } = useSpring({ number: value });
  return <animated.text>{number.to(n => n.toFixed(0))}</animated.text>;
}

场景 4:App 启动 Logo 动画

  • 需求:播放设计师提供的品牌 Logo 动效
  • 推荐lottie-react-native(RN)或 lottie-web(Web)
  • 原因:Lottie 是行业标准矢量动画格式,无需编码

📌 关键结论

  • Web 项目

    • 简单过渡 → react-transition-group
    • 交互动画/布局动画 → framer-motion
    • 物理模拟/跨平台 → react-spring
  • React Native 项目

    • 高性能交互动画 → react-native-reanimated
    • 播放 Lottie 动画 → lottie-react-native
    • 避免使用 react-native-animatable
  • 通用原则

    • 优先选择 原生线程执行 的方案(如 Reanimated)
    • 复杂动画尽量 避免在 JS 线程运行
    • 设计师交付的动效优先考虑 Lottie 格式

最终,没有“最好”的库,只有“最合适”的工具。理解每个库的底层机制和设计哲学,才能在正确的时间选用正确的武器。

如何选择: react-spring vs framer-motion vs lottie-react-native vs react-native-animatable vs react-native-reanimated vs react-transition-group

  • react-spring:

    选择 react-spring 如果你需要基于物理弹簧模型的自然动画效果(如弹性、阻尼),并希望在 Web 或 React Native(通过 @react-spring/native)之间共享动画逻辑。它比 CSS 过渡更灵活,适合数据可视化、复杂状态插值或需要精确控制动画曲线的场景,但需注意其声明式 API 可能带来额外的认知负担。

  • framer-motion:

    选择 framer-motion 如果你正在构建 Web 应用,需要高度声明式、可组合的动画 API,并希望利用其内置的布局动画(layout animations)、手势交互(drag, hover)和共享元素过渡。它适合中等复杂度的 UI 动画,如卡片展开、路由切换、悬停反馈等,但不适用于需要精细控制或极致性能的复杂物理模拟。

  • lottie-react-native:

    选择 lottie-react-native 如果你需要在 React Native 应用中嵌入由 After Effects 导出的 Lottie JSON 动画文件(例如加载指示器、品牌动效或复杂矢量动画)。它不适用于程序化生成的动画逻辑,而是作为设计师交付资产的播放器,适合复用预制作动画内容而非编写代码驱动的动态行为。

  • react-native-animatable:

    选择 react-native-animatable 仅当你需要快速实现简单的内置动画(如 fadeIn、bounceIn)且项目对性能要求不高。该库已多年未积极维护,所有动画均在 JavaScript 线程运行,可能导致卡顿,不推荐用于新项目;应优先评估 react-native-reanimated 或其他现代替代方案。

  • react-native-reanimated:

    选择 react-native-reanimated 如果你在 React Native 中需要高性能、流畅的动画(如手势驱动交互动画、自定义转场),尤其是当动画必须在 UI 线程运行以避免 JS 线程阻塞时。它学习曲线较陡,但提供了底层原生动画能力,适合构建复杂交互(如可拖拽面板、自定义导航转场)或对 60fps 有严格要求的场景。

  • react-transition-group:

    选择 react-transition-group 如果你只需要处理组件的进入(enter)、退出(exit)和出场(appear)过渡,尤其是配合 CSS 类名或内联样式实现简单的淡入淡出、滑动效果。它轻量、专注,适合路由切换、模态框显示/隐藏等场景,但不提供高级动画能力(如手势、物理模拟或原生线程优化);若需更强大功能,应考虑 framer-motionreact-spring

react-spring的README


react-spring

A spring-physics first animation library
giving you flexible tools to confidently cast your ideas


Chat on Discord


react-spring is a cross-platform spring-physics first animation library.

It's as simple as:

const styles = useSpring({
  from: {
    opacity: 0
  },
  to: {
    opacity: 1
  }
})

<animated.div style={styles} />

Just a small bit about us:

  • Cross-Platform: We support react-dom, react-native, react-three-fiber, react-konva & react-zdog.
  • Versatile: Be declarative with your animations or if you prefer, imperative.
  • Spring-Physics First: By default animation use springs for fluid interactivity, but we support durations with easings as well.

There's a lot more to be had! Give it a try and find out.

Getting Started

⚡️ Jump Start

# Install the entire library
npm install react-spring
# or just install your specific target (recommended)
npm install @react-spring/web
import { animated, useSpring } from '@react-spring/web'

const FadeIn = ({ isVisible, children }) => {
  const styles = useSpring({
    opacity: isVisible ? 1 : 0,
    y: isVisible ? 0 : 24,
  })

  return <animated.div style={styles}>{children}</animated.div>
}

It's as simple as that to create scroll-in animations when value of isVisible is toggled.

📖 Documentation and Examples

More documentation on the project can be found here.

Pages contain their own examples which you can check out there, or open in codesandbox for a more in-depth view!


📣 What others say

Used by

And many others...

Backers

Thank you to all our backers! 🙏 If you want to join them here, then consider contributing to our Opencollective.

Contributors

This project exists thanks to all the people who contribute.