rn-reanimated

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

React Native Reanimated — Best Practices & 60fps Guide

React Native Reanimated — 最佳实践与60fps指南

Reanimated 4.x / Worklets 0.7.x / React Native 0.80+ (New Architecture required)
适配 Reanimated 4.x / Worklets 0.7.x / React Native 0.80+(需启用新架构)

Critical Rules

关键规则

  1. Babel plugin must be LAST in
    babel.config.js
    plugins array.
  2. Never use React state (
    useState
    ) for values that drive animations.
    Use
    useSharedValue
    .
  3. Never call
    withTiming
    /
    withSpring
    inside gesture
    .onUpdate
    callbacks.
    Assign the event value directly for smooth tracking; use spring/timing only in
    .onEnd
    .
  4. Always cancel animations before starting new ones when gestures begin:
    cancelAnimation(sv)
    .
  5. Always pass
    velocity
    from gesture events into
    withSpring
    for natural feel.
  6. Always wrap the app in
    <GestureHandlerRootView style={{ flex: 1 }}>
    .
    Gestures won't work without it.
  7. Always cancel animations on unmount via
    useEffect
    cleanup.
  8. Respect reduced motion — use
    ReduceMotion.System
    or
    useReducedMotion()
    .
  1. Babel插件必须位于
    babel.config.js
    插件数组的最后一位
  2. 绝不能使用React状态(
    useState
    )作为动画驱动值
    ,请使用
    useSharedValue
  3. 绝不要在手势
    .onUpdate
    回调中调用
    withTiming
    /
    withSpring
    。直接赋值事件值以实现平滑跟踪;仅在
    .onEnd
    中使用弹簧/计时动画。
  4. 在开始新动画前务必取消原有动画:在手势开始时调用
    cancelAnimation(sv)
  5. 务必从手势事件中传入
    velocity
    参数
    withSpring
    ,以获得自然的动画效果。
  6. 务必用
    <GestureHandlerRootView style={{ flex: 1 }}>
    包裹整个应用
    ,否则手势将无法正常工作。
  7. 务必在组件卸载时取消动画,通过
    useEffect
    的清理函数实现。
  8. 遵循减少动画的系统设置——使用
    ReduceMotion.System
    useReducedMotion()

Code Review & Upgrade Action

代码审查与升级步骤

When the user asks to review, check, audit, or upgrade their Reanimated code, follow this procedure:
  1. Scan all files containing Reanimated imports (
    react-native-reanimated
    ,
    react-native-gesture-handler
    ).
  2. Check each file against every rule below and the Anti-Patterns table. For each violation found, collect: file path, line number, what's wrong, and the fix.
  3. Report findings to the user in a clear table format:
| File | Line | Issue | Severity | Fix |
|------|------|-------|----------|-----|
| src/Card.tsx | 12 | useState driving animation | HIGH | Replace with useSharedValue |
| src/Sheet.tsx | 45 | Missing cancelAnimation in onBegin | HIGH | Add cancelAnimation(sv) |
| src/List.tsx | 78 | Math.random() as key | MEDIUM | Use stable unique ID |
  1. Severity levels:
    • CRITICAL: Will crash or break animations (missing GestureHandlerRootView, hooks in worklets, Babel plugin order wrong)
    • HIGH: Causes jank/dropped frames (useState for animation, withSpring in onUpdate, missing cancelAnimation, missing velocity)
    • MEDIUM: Sub-optimal but works (no reduced motion support, no animation cleanup on unmount, shadow on Android)
    • LOW: Style/convention (missing spring presets, could use better easing)
  2. Ask the user: "I found X issues in Y files. Want me to fix all of them automatically?" — then apply all fixes if confirmed.
  3. After fixing, re-scan to confirm zero remaining violations and report:
    • Total issues found → fixed
    • Files modified
    • Expected performance improvement (e.g., "Removed 3 JS-thread bottlenecks — gestures should now track at 60fps")
当用户要求审查、检查、审计或升级其Reanimated代码时,请遵循以下流程:
  1. 扫描所有包含Reanimated导入(
    react-native-reanimated
    react-native-gesture-handler
    )的文件。
  2. 逐一检查每个文件是否符合以下规则及反模式表格。对于发现的每个问题,记录:文件路径、行号、问题描述及修复方案。
  3. 以清晰的表格格式向用户报告发现的问题:
| 文件 | 行号 | 问题 | 严重程度 | 修复方案 |
|------|------|-------|----------|-----|
| src/Card.tsx | 12 | 使用useState驱动动画 | 高 | 替换为useSharedValue |
| src/Sheet.tsx | 45 | 手势开始时缺少cancelAnimation | 高 | 添加cancelAnimation(sv) |
| src/List.tsx | 78 | 使用Math.random()作为key | 中 | 使用稳定的唯一ID |
  1. 严重程度等级
    • CRITICAL(致命):会导致崩溃或动画完全失效(缺少GestureHandlerRootView、在Worklets中使用hooks、Babel插件顺序错误)
    • HIGH(高):导致动画卡顿/丢帧(使用useState驱动动画、在onUpdate中使用withSpring、缺少cancelAnimation、缺少velocity参数)
    • MEDIUM(中):实现不够优化但可正常运行(未支持减少动画、未在卸载时清理动画、Android端使用阴影动画)
    • LOW(低):风格/规范问题(缺少弹簧预设、可使用更优的缓动函数)
  2. 询问用户:“我在Y个文件中发现了X个问题,需要我自动修复所有问题吗?”——若用户确认,则应用所有修复方案。
  3. 修复完成后,重新扫描以确认无剩余问题,并向用户报告:
    • 发现并修复的问题总数
    • 修改的文件列表
    • 预期的性能提升(例如:“移除了3个JS线程瓶颈——手势现在应能以60fps流畅跟踪”)

What to Check (scan checklist)

检查清单

  • useState
    /
    setState
    used for values that drive animations → replace with
    useSharedValue
  • withTiming
    /
    withSpring
    called inside gesture
    .onUpdate
    → replace with direct assignment
  • .value
    read directly in JSX render → wrap in
    useAnimatedStyle
  • Animation created in render return → move to handler/effect
  • Missing
    cancelAnimation
    in gesture
    .onBegin
    → add it
  • Missing
    velocity
    in
    withSpring
    after gesture
    .onEnd
    → add
    { velocity: e.velocityX }
  • Shadow properties animated on Android → switch to
    elevation
  • Math.random()
    used as list item key → use stable ID
  • Large staggered delays on 100+ items → cap with
    Math.min()
  • Missing
    GestureHandlerRootView
    wrapping the app
  • Missing animation cleanup in
    useEffect
    return
  • Missing mounted guard for
    runOnJS
    in
    useAnimatedReaction
  • 'worklet'
    directive missing in custom worklet functions
  • React hooks used inside worklets
  • async/await inside worklets
  • Large objects/arrays captured in worklet closures
  • Babel plugin not last in plugins array
  • Animating
    borderWidth
    ,
    shadowOffset
    ,
    shadowRadius
    on Android
  • Missing
    overflow: 'hidden'
    for
    borderRadius
    animation on Android
  • No reduced motion handling (
    ReduceMotion.System
    or
    useReducedMotion()
    )
  • Animated.FlatList
    missing
    skipEnteringExitingAnimations
    for initial render
  • 使用
    useState
    /
    setState
    驱动动画值 → 替换为
    useSharedValue
  • 在手势
    .onUpdate
    中调用
    withTiming
    /
    withSpring
    → 替换为直接赋值
  • 在JSX渲染中直接读取
    sv.value
    → 用
    useAnimatedStyle
    包裹
  • 在render返回值中创建
    withTiming()
    → 移至事件处理函数/
    useEffect
  • 手势
    .onBegin
    中缺少
    cancelAnimation
    → 添加该函数
  • 手势
    .onEnd
    withSpring
    缺少
    velocity
    参数 → 添加
    { velocity: e.velocityX }
  • 在Android端动画阴影属性 → 切换为使用
    elevation
  • 使用
    Math.random()
    作为列表项key → 使用稳定ID
  • 100+个元素使用大跨度延迟 → 用
    Math.min()
    限制延迟
  • 应用未被
    GestureHandlerRootView
    包裹
  • useEffect
    返回中缺少动画清理逻辑
  • useAnimatedReaction
    中调用
    runOnJS
    时未检查组件是否挂载
  • 自定义Worklet函数缺少
    'worklet'
    指令
  • 在Worklets中使用React hooks
  • 在Worklets中使用async/await
  • Worklet闭包中捕获大型对象/数组
  • Babel插件未位于插件数组最后一位
  • 在Android端动画
    borderWidth
    shadowOffset
    shadowRadius
  • Android端动画
    borderRadius
    时缺少
    overflow: 'hidden'
  • 未处理减少动画的设置(
    ReduceMotion.System
    useReducedMotion()
  • Animated.FlatList
    初始渲染时缺少
    skipEnteringExitingAnimations

Installation

安装步骤

bash
npm install react-native-reanimated react-native-worklets react-native-gesture-handler
js
// babel.config.js
module.exports = {
  presets: ['module:metro-react-native-babel-preset'],
  plugins: ['react-native-reanimated/plugin'], // MUST be last
};
After install: clear Metro cache (
npx react-native start --reset-cache
), rebuild native (
pod install
/
gradlew clean
).
bash
npm install react-native-reanimated react-native-worklets react-native-gesture-handler
js
// babel.config.js
module.exports = {
  presets: ['module:metro-react-native-babel-preset'],
  plugins: ['react-native-reanimated/plugin'], // 必须放在最后
};
安装完成后:清除Metro缓存(
npx react-native start --reset-cache
),重新构建原生代码(
pod install
/
gradlew clean
)。

Core Pattern — The Only Pattern You Need

核心模式——唯一需要掌握的模式

tsx
const offset = useSharedValue(0);

const animatedStyle = useAnimatedStyle(() => ({
  transform: [{ translateX: offset.value }],
}));

const animate = () => {
  offset.value = withSpring(100, { damping: 15, stiffness: 150 });
};

<Animated.View style={[styles.box, animatedStyle]} />;
tsx
const offset = useSharedValue(0);

const animatedStyle = useAnimatedStyle(() => ({
  transform: [{ translateX: offset.value }],
}));

const animate = () => {
  offset.value = withSpring(100, { damping: 15, stiffness: 150 });
};

<Animated.View style={[styles.box, animatedStyle]} />;

Animation Function Selection

动画函数选择指南

ContextUseWhy
During gesture (finger down)Direct assignmentFollows finger at 60fps
Gesture release
withSpring
+ velocity
Natural physics feel
Fixed-duration transition
withTiming
(200-500ms)
Predictable timing
Momentum/fling
withDecay
Natural deceleration
Toggle state
withSpring
Bouncy feedback
场景使用函数原因
手势操作中(手指按下时)直接赋值以60fps跟踪手指移动
手势释放时
withSpring
+ velocity参数
获得符合物理规律的自然效果
固定时长过渡
withTiming
(200-500ms)
可预测的计时效果
动量/甩动效果
withDecay
自然减速效果
状态切换
withSpring
带弹性的反馈效果

Spring Presets

弹簧预设参数

ts
const SPRING = {
  gentle:  { damping: 15, stiffness: 50 },   // Slow, smooth
  normal:  { damping: 10, stiffness: 100 },  // Balanced
  snappy:  { damping: 20, stiffness: 300 },  // Quick, snappy
  noBounce:{ damping: 30, stiffness: 200 },  // Critically damped
};
ts
const SPRING = {
  gentle:  { damping: 15, stiffness: 50 },   // 缓慢、平滑
  normal:  { damping: 10, stiffness: 100 },  // 平衡
  snappy:  { damping: 20, stiffness: 300 },  // 快速、干脆
  noBounce:{ damping: 30, stiffness: 200 },  // 临界阻尼(无弹跳)
};

Gesture Pattern (Pan with Spring Back)

手势模式(带弹簧回弹的拖动手势)

tsx
const offsetX = useSharedValue(0);
const startX = useSharedValue(0);

const pan = Gesture.Pan()
  .onBegin(() => {
    cancelAnimation(offsetX);
    startX.value = offsetX.value;
  })
  .onUpdate((e) => {
    offsetX.value = startX.value + e.translationX; // Direct assignment
  })
  .onEnd((e) => {
    offsetX.value = withSpring(0, { velocity: e.velocityX, damping: 15 });
  });
tsx
const offsetX = useSharedValue(0);
const startX = useSharedValue(0);

const pan = Gesture.Pan()
  .onBegin(() => {
    cancelAnimation(offsetX);
    startX.value = offsetX.value;
  })
  .onUpdate((e) => {
    offsetX.value = startX.value + e.translationX; // 直接赋值
  })
  .onEnd((e) => {
    offsetX.value = withSpring(0, { velocity: e.velocityX, damping: 15 });
  });

Performance Targets

性能目标

  • Frame budget: 16.67ms (60fps) / 8.33ms (120fps ProMotion)
  • JS thread: < 8ms per frame
  • UI thread: < 10ms per frame
  • Animated properties per component: Keep to 2-4 max
  • 单帧预算:16.67ms(60fps)/ 8.33ms(120fps ProMotion)
  • JS线程:每帧耗时<8ms
  • UI线程:每帧耗时<10ms
  • 单个组件的动画属性数量:最多保持2-4个

Anti-Patterns to Fix on Sight

需立即修复的反模式

Anti-PatternFix
useState
driving animation values
Replace with
useSharedValue
withTiming(event.translationX)
in
.onUpdate
Direct assign:
sv.value = event.translationX
Reading
sv.value
in JSX render
Use
useAnimatedStyle
Creating
withTiming()
in render return
Move to event handler /
useEffect
Missing
cancelAnimation
on gesture begin
Add
cancelAnimation(sv)
in
.onBegin
Missing velocity on spring after gestureAdd
{ velocity: event.velocityX }
Shadow animation on AndroidUse
elevation
instead
Math.random()
as list item key
Use stable unique IDs
100+ items with
FadeIn.delay(i * 10)
Cap delay:
Math.min(i * 50, 1000)
反模式修复方案
使用
useState
驱动动画值
替换为
useSharedValue
.onUpdate
中使用
withTiming(event.translationX)
直接赋值:
sv.value = event.translationX
在JSX渲染中读取
sv.value
使用
useAnimatedStyle
在render返回值中创建
withTiming()
移至事件处理函数/
useEffect
手势开始时缺少
cancelAnimation
.onBegin
中添加
cancelAnimation(sv)
手势结束后弹簧动画缺少velocity参数添加
{ velocity: event.velocityX }
Android端动画阴影属性改用
elevation
使用
Math.random()
作为列表项key
使用稳定的唯一ID
100+个元素使用
FadeIn.delay(i * 10)
限制延迟:
Math.min(i * 50, 1000)

Platform-Specific Rules

平台特定规则

Android

Android

  • Use
    elevation
    instead of shadow properties for animated shadows.
  • Use
    overflow: 'hidden'
    on parent for smooth
    borderRadius
    animation.
  • Reduce animation complexity on low-end devices (skip rotation, limit properties).
  • Avoid animating
    borderWidth
    ,
    shadowOffset
    ,
    shadowRadius
    — they jank on Android.
  • 动画阴影时使用
    elevation
    而非阴影属性。
  • 为父组件设置
    overflow: 'hidden'
    以实现平滑的
    borderRadius
    动画。
  • 在低端设备上降低动画复杂度(跳过旋转动画、限制动画属性数量)。
  • 避免动画
    borderWidth
    shadowOffset
    shadowRadius
    ——这些属性在Android端会导致卡顿。

iOS

iOS

  • Shadow properties (
    shadowOpacity
    ,
    shadowRadius
    ,
    shadowOffset
    ) are animatable.
  • ProMotion displays support 120fps — use spring animations to benefit from variable refresh.
  • Use
    enableLayoutAnimations(true)
    (enabled by default).
  • 阴影属性(
    shadowOpacity
    shadowRadius
    shadowOffset
    )支持动画。
  • ProMotion显示屏支持120fps——使用弹簧动画以充分利用可变刷新率。
  • 使用
    enableLayoutAnimations(true)
    (默认已启用)。

Memory Management

内存管理

tsx
useEffect(() => {
  return () => {
    cancelAnimation(offset);
    cancelAnimation(scale);
  };
}, []);
For reactions that call
runOnJS
, guard with a mounted flag:
tsx
const isMounted = useSharedValue(true);
useEffect(() => () => { isMounted.value = false; }, []);

useAnimatedReaction(
  () => progress.value,
  (val) => {
    if (val >= 1 && isMounted.value) runOnJS(onComplete)();
  }
);
tsx
useEffect(() => {
  return () => {
    cancelAnimation(offset);
    cancelAnimation(scale);
  };
}, []);
对于调用
runOnJS
useAnimatedReaction
,需添加组件挂载状态判断:
tsx
const isMounted = useSharedValue(true);
useEffect(() => () => { isMounted.value = false; }, []);

useAnimatedReaction(
  () => progress.value,
  (val) => {
    if (val >= 1 && isMounted.value) runOnJS(onComplete)();
  }
);

Worklet Rules

Worklets规则

  • 'worklet'
    directive must be the first statement in the function body.
  • Auto-workletized contexts (no manual directive needed):
    useAnimatedStyle
    ,
    useAnimatedProps
    ,
    useDerivedValue
    ,
    useAnimatedReaction
    ,
    useAnimatedScrollHandler
    , gesture callbacks.
  • Never use React hooks, async/await, DOM APIs, or
    localStorage
    inside worklets.
  • Never close over large arrays/objects — they get copied to the UI thread.
  • Use
    runOnJS(fn)(args)
    to call JS from worklets; use
    runOnUI(fn)(args)
    to call worklets from JS.
  • 'worklet'
    指令必须是函数体的第一条语句
  • 自动Worklet化的上下文(无需手动添加指令):
    useAnimatedStyle
    useAnimatedProps
    useDerivedValue
    useAnimatedReaction
    useAnimatedScrollHandler
    、手势回调。
  • 绝不能在Worklets中使用React hooks、async/await、DOM API或
    localStorage
  • 绝不能在Worklet闭包中捕获大型数组/对象——它们会被复制到UI线程。
  • 使用
    runOnJS(fn)(args)
    从Worklets调用JS代码;使用
    runOnUI(fn)(args)
    从JS调用Worklets。

Layout Animations Quick Reference

布局动画快速参考

tsx
<Animated.View
  entering={FadeInUp.delay(index * 50).springify().damping(12)}
  exiting={FadeOut.duration(200)}
  layout={Layout.springify()}
/>
  • Use staggered delays for lists:
    delay(index * 50)
    .
  • Use stable unique keys — never
    Math.random()
    .
  • Use
    skipEnteringExitingAnimations
    on
    Animated.FlatList
    for initial render.
  • Handle reduced motion:
    entering={reducedMotion ? undefined : FadeIn}
    .
tsx
<Animated.View
  entering={FadeInUp.delay(index * 50).springify().damping(12)}
  exiting={FadeOut.duration(200)}
  layout={Layout.springify()}
/>
  • 列表动画使用交错延迟:
    delay(index * 50)
  • 使用稳定的唯一key——绝不能用
    Math.random()
  • Animated.FlatList
    初始渲染时使用
    skipEnteringExitingAnimations
  • 处理减少动画的设置:
    entering={reducedMotion ? undefined : FadeIn}

Debugging Checklist

调试清单

  1. Babel plugin is last in plugins array
  2. Metro cache cleared (
    --reset-cache
    )
  3. Native code rebuilt (
    pod install
    /
    gradlew clean
    )
  4. 'worklet'
    directive present in custom worklet functions
  5. Hooks only at component top level (never in worklets)
  6. Shared values used for animation state
  7. GestureHandlerRootView
    wraps the app
  8. Animation functions assigned to
    .value
    (not called standalone)
  9. Previous animations cancelled before new ones
  1. Babel插件位于插件数组最后一位
  2. 已清除Metro缓存(
    --reset-cache
  3. 已重新构建原生代码(
    pod install
    /
    gradlew clean
  4. 自定义Worklet函数包含
    'worklet'
    指令
  5. Hooks仅在组件顶层使用(绝不在Worklets中)
  6. 使用共享值存储动画状态
  7. 应用被
    GestureHandlerRootView
    包裹
  8. 动画函数被赋值给
    .value
    (而非直接调用)
  9. 开始新动画前已取消原有动画

Reference Files

参考文档

For detailed API docs, examples, and patterns, read these files as needed:
  • Fundamentals & Getting Started: Installation, prerequisites, New Architecture setup, core concepts (Shared Values, Animated Styles, Animated Components), first animation walkthrough, architecture overview.
  • Animation Functions:
    withTiming
    ,
    withSpring
    ,
    withDecay
    , modifiers (
    withDelay
    ,
    withRepeat
    ,
    withSequence
    ,
    withClamp
    ), easing functions, spring physics, callbacks.
  • Hooks & Utilities: All hooks (
    useSharedValue
    ,
    useAnimatedStyle
    ,
    useAnimatedProps
    ,
    useDerivedValue
    ,
    useAnimatedReaction
    ,
    useAnimatedRef
    ,
    useAnimatedScrollHandler
    ,
    useScrollViewOffset
    ,
    useAnimatedKeyboard
    ,
    useAnimatedSensor
    ,
    useFrameCallback
    ), utility functions (
    runOnJS
    ,
    runOnUI
    ,
    cancelAnimation
    ,
    interpolate
    ,
    interpolateColor
    ,
    clamp
    ).
  • Worklets Deep Dive: Threading model,
    'worklet'
    directive rules, closure capture, custom runtimes, thread communication (
    runOnUI
    ,
    runOnJS
    ,
    runOnUISync
    ), scheduling, debugging worklets.
  • Layout Animations: Entering/exiting animations (Fade, Slide, Zoom, Bounce, Flip, Rotate, etc.), layout transitions, keyframe animations, list animations, shared element transitions.
  • Gestures Integration: All gesture types (Tap, Pan, Pinch, Rotation, Fling, LongPress), gesture configuration, composition (
    Simultaneous
    ,
    Exclusive
    ,
    Race
    ), common patterns (swipeable item, bottom sheet, pull-to-refresh, carousel, photo viewer).
  • Best Practices & Performance: 60fps performance principles, animation optimization patterns, anti-patterns to avoid, debugging strategies, platform-specific guidelines (Android/iOS), memory management, complex animation patterns.
  • Troubleshooting: Installation issues, build errors, runtime errors, animation issues, gesture issues, performance issues, platform-specific issues, error message reference.
如需详细的API文档、示例和模式,请按需阅读以下文件:
  • 基础与入门:安装、前置条件、新架构设置、核心概念(共享值、动画样式、动画组件)、第一个动画实现教程、架构概述。
  • 动画函数
    withTiming
    withSpring
    withDecay
    、修饰符(
    withDelay
    withRepeat
    withSequence
    withClamp
    )、缓动函数、弹簧物理、回调函数。
  • Hooks与工具函数:所有Hooks(
    useSharedValue
    useAnimatedStyle
    useAnimatedProps
    useDerivedValue
    useAnimatedReaction
    useAnimatedRef
    useAnimatedScrollHandler
    useScrollViewOffset
    useAnimatedKeyboard
    useAnimatedSensor
    useFrameCallback
    )、工具函数(
    runOnJS
    runOnUI
    cancelAnimation
    interpolate
    interpolateColor
    clamp
    )。
  • Worklets深度解析:线程模型、
    'worklet'
    指令规则、闭包捕获、自定义运行时、线程通信(
    runOnUI
    runOnJS
    runOnUISync
    )、调度、Worklets调试。
  • 布局动画:进入/退出动画(淡入、滑动、缩放、弹跳、翻转、旋转等)、布局过渡、关键帧动画、列表动画、共享元素过渡。
  • 手势集成:所有手势类型(点击、拖动、捏合、旋转、甩动、长按)、手势配置、组合(
    Simultaneous
    Exclusive
    Race
    )、常见模式(可滑动项、底部弹窗、下拉刷新、轮播、图片查看器)。
  • 最佳实践与性能优化:60fps性能原则、动画优化模式、需避免的反模式、调试策略、平台特定指南(Android/iOS)、内存管理、复杂动画模式。
  • 故障排除:安装问题、构建错误、运行时错误、动画问题、手势问题、性能问题、平台特定问题、错误信息参考。