rn-reanimated
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseReact 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
关键规则
- Babel plugin must be LAST in plugins array.
babel.config.js - Never use React state () for values that drive animations. Use
useState.useSharedValue - Never call /
withTiminginside gesturewithSpringcallbacks. Assign the event value directly for smooth tracking; use spring/timing only in.onUpdate..onEnd - Always cancel animations before starting new ones when gestures begin: .
cancelAnimation(sv) - Always pass from gesture events into
velocityfor natural feel.withSpring - Always wrap the app in . Gestures won't work without it.
<GestureHandlerRootView style={{ flex: 1 }}> - Always cancel animations on unmount via cleanup.
useEffect - Respect reduced motion — use or
ReduceMotion.System.useReducedMotion()
- Babel插件必须位于插件数组的最后一位。
babel.config.js - 绝不能使用React状态()作为动画驱动值,请使用
useState。useSharedValue - 绝不要在手势回调中调用
.onUpdate/withTiming。直接赋值事件值以实现平滑跟踪;仅在withSpring中使用弹簧/计时动画。.onEnd - 在开始新动画前务必取消原有动画:在手势开始时调用。
cancelAnimation(sv) - 务必从手势事件中传入参数到
velocity,以获得自然的动画效果。withSpring - 务必用包裹整个应用,否则手势将无法正常工作。
<GestureHandlerRootView style={{ flex: 1 }}> - 务必在组件卸载时取消动画,通过的清理函数实现。
useEffect - 遵循减少动画的系统设置——使用或
ReduceMotion.System。useReducedMotion()
Code Review & Upgrade Action
代码审查与升级步骤
When the user asks to review, check, audit, or upgrade their Reanimated code, follow this procedure:
- Scan all files containing Reanimated imports (,
react-native-reanimated).react-native-gesture-handler - 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.
- 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 |-
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)
-
Ask the user: "I found X issues in Y files. Want me to fix all of them automatically?" — then apply all fixes if confirmed.
-
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代码时,请遵循以下流程:
- 扫描所有包含Reanimated导入(、
react-native-reanimated)的文件。react-native-gesture-handler - 逐一检查每个文件是否符合以下规则及反模式表格。对于发现的每个问题,记录:文件路径、行号、问题描述及修复方案。
- 以清晰的表格格式向用户报告发现的问题:
| 文件 | 行号 | 问题 | 严重程度 | 修复方案 |
|------|------|-------|----------|-----|
| src/Card.tsx | 12 | 使用useState驱动动画 | 高 | 替换为useSharedValue |
| src/Sheet.tsx | 45 | 手势开始时缺少cancelAnimation | 高 | 添加cancelAnimation(sv) |
| src/List.tsx | 78 | 使用Math.random()作为key | 中 | 使用稳定的唯一ID |-
严重程度等级:
- CRITICAL(致命):会导致崩溃或动画完全失效(缺少GestureHandlerRootView、在Worklets中使用hooks、Babel插件顺序错误)
- HIGH(高):导致动画卡顿/丢帧(使用useState驱动动画、在onUpdate中使用withSpring、缺少cancelAnimation、缺少velocity参数)
- MEDIUM(中):实现不够优化但可正常运行(未支持减少动画、未在卸载时清理动画、Android端使用阴影动画)
- LOW(低):风格/规范问题(缺少弹簧预设、可使用更优的缓动函数)
-
询问用户:“我在Y个文件中发现了X个问题,需要我自动修复所有问题吗?”——若用户确认,则应用所有修复方案。
-
修复完成后,重新扫描以确认无剩余问题,并向用户报告:
- 发现并修复的问题总数
- 修改的文件列表
- 预期的性能提升(例如:“移除了3个JS线程瓶颈——手势现在应能以60fps流畅跟踪”)
What to Check (scan checklist)
检查清单
- /
useStateused for values that drive animations → replace withsetStateuseSharedValue - /
withTimingcalled inside gesturewithSpring→ replace with direct assignment.onUpdate - read directly in JSX render → wrap in
.valueuseAnimatedStyle - Animation created in render return → move to handler/effect
- Missing in gesture
cancelAnimation→ add it.onBegin - Missing in
velocityafter gesturewithSpring→ add.onEnd{ velocity: e.velocityX } - Shadow properties animated on Android → switch to
elevation - used as list item key → use stable ID
Math.random() - Large staggered delays on 100+ items → cap with
Math.min() - Missing wrapping the app
GestureHandlerRootView - Missing animation cleanup in return
useEffect - Missing mounted guard for in
runOnJSuseAnimatedReaction - directive missing in custom worklet functions
'worklet' - 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,shadowOffseton AndroidshadowRadius - Missing for
overflow: 'hidden'animation on AndroidborderRadius - No reduced motion handling (or
ReduceMotion.System)useReducedMotion() - missing
Animated.FlatListfor initial renderskipEnteringExitingAnimations
- 使用/
useState驱动动画值 → 替换为setStateuseSharedValue - 在手势中调用
.onUpdate/withTiming→ 替换为直接赋值withSpring - 在JSX渲染中直接读取→ 用
sv.value包裹useAnimatedStyle - 在render返回值中创建→ 移至事件处理函数/
withTiming()useEffect - 手势中缺少
.onBegin→ 添加该函数cancelAnimation - 手势后
.onEnd缺少withSpring参数 → 添加velocity{ velocity: e.velocityX } - 在Android端动画阴影属性 → 切换为使用
elevation - 使用作为列表项key → 使用稳定ID
Math.random() - 100+个元素使用大跨度延迟 → 用限制延迟
Math.min() - 应用未被包裹
GestureHandlerRootView - 返回中缺少动画清理逻辑
useEffect - 中调用
useAnimatedReaction时未检查组件是否挂载runOnJS - 自定义Worklet函数缺少指令
'worklet' - 在Worklets中使用React hooks
- 在Worklets中使用async/await
- Worklet闭包中捕获大型对象/数组
- Babel插件未位于插件数组最后一位
- 在Android端动画、
borderWidth、shadowOffsetshadowRadius - Android端动画时缺少
borderRadiusoverflow: 'hidden' - 未处理减少动画的设置(或
ReduceMotion.System)useReducedMotion() - 初始渲染时缺少
Animated.FlatListskipEnteringExitingAnimations
Installation
安装步骤
bash
npm install react-native-reanimated react-native-worklets react-native-gesture-handlerjs
// 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 (), rebuild native ( / ).
npx react-native start --reset-cachepod installgradlew cleanbash
npm install react-native-reanimated react-native-worklets react-native-gesture-handlerjs
// babel.config.js
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: ['react-native-reanimated/plugin'], // 必须放在最后
};安装完成后:清除Metro缓存(),重新构建原生代码( / )。
npx react-native start --reset-cachepod installgradlew cleanCore 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
动画函数选择指南
| Context | Use | Why |
|---|---|---|
| During gesture (finger down) | Direct assignment | Follows finger at 60fps |
| Gesture release | | Natural physics feel |
| Fixed-duration transition | | Predictable timing |
| Momentum/fling | | Natural deceleration |
| Toggle state | | Bouncy feedback |
| 场景 | 使用函数 | 原因 |
|---|---|---|
| 手势操作中(手指按下时) | 直接赋值 | 以60fps跟踪手指移动 |
| 手势释放时 | | 获得符合物理规律的自然效果 |
| 固定时长过渡 | | 可预测的计时效果 |
| 动量/甩动效果 | | 自然减速效果 |
| 状态切换 | | 带弹性的反馈效果 |
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-Pattern | Fix |
|---|---|
| Replace with |
| Direct assign: |
Reading | Use |
Creating | Move to event handler / |
Missing | Add |
| Missing velocity on spring after gesture | Add |
| Shadow animation on Android | Use |
| Use stable unique IDs |
100+ items with | Cap delay: |
| 反模式 | 修复方案 |
|---|---|
使用 | 替换为 |
在 | 直接赋值: |
在JSX渲染中读取 | 使用 |
在render返回值中创建 | 移至事件处理函数/ |
手势开始时缺少 | 在 |
| 手势结束后弹簧动画缺少velocity参数 | 添加 |
| Android端动画阴影属性 | 改用 |
使用 | 使用稳定的唯一ID |
100+个元素使用 | 限制延迟: |
Platform-Specific Rules
平台特定规则
Android
Android
- Use instead of shadow properties for animated shadows.
elevation - Use on parent for smooth
overflow: 'hidden'animation.borderRadius - Reduce animation complexity on low-end devices (skip rotation, limit properties).
- Avoid animating ,
borderWidth,shadowOffset— they jank on Android.shadowRadius
- 动画阴影时使用而非阴影属性。
elevation - 为父组件设置以实现平滑的
overflow: 'hidden'动画。borderRadius - 在低端设备上降低动画复杂度(跳过旋转动画、限制动画属性数量)。
- 避免动画、
borderWidth、shadowOffset——这些属性在Android端会导致卡顿。shadowRadius
iOS
iOS
- Shadow properties (,
shadowOpacity,shadowRadius) are animatable.shadowOffset - ProMotion displays support 120fps — use spring animations to benefit from variable refresh.
- Use (enabled by default).
enableLayoutAnimations(true)
- 阴影属性(、
shadowOpacity、shadowRadius)支持动画。shadowOffset - ProMotion显示屏支持120fps——使用弹簧动画以充分利用可变刷新率。
- 使用(默认已启用)。
enableLayoutAnimations(true)
Memory Management
内存管理
tsx
useEffect(() => {
return () => {
cancelAnimation(offset);
cancelAnimation(scale);
};
}, []);For reactions that call , guard with a mounted flag:
runOnJStsx
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);
};
}, []);对于调用的,需添加组件挂载状态判断:
runOnJSuseAnimatedReactiontsx
const isMounted = useSharedValue(true);
useEffect(() => () => { isMounted.value = false; }, []);
useAnimatedReaction(
() => progress.value,
(val) => {
if (val >= 1 && isMounted.value) runOnJS(onComplete)();
}
);Worklet Rules
Worklets规则
- directive must be the first statement in the function body.
'worklet' - Auto-workletized contexts (no manual directive needed): ,
useAnimatedStyle,useAnimatedProps,useDerivedValue,useAnimatedReaction, gesture callbacks.useAnimatedScrollHandler - Never use React hooks, async/await, DOM APIs, or inside worklets.
localStorage - Never close over large arrays/objects — they get copied to the UI thread.
- Use to call JS from worklets; use
runOnJS(fn)(args)to call worklets from JS.runOnUI(fn)(args)
- 指令必须是函数体的第一条语句。
'worklet' - 自动Worklet化的上下文(无需手动添加指令):、
useAnimatedStyle、useAnimatedProps、useDerivedValue、useAnimatedReaction、手势回调。useAnimatedScrollHandler - 绝不能在Worklets中使用React hooks、async/await、DOM API或。
localStorage - 绝不能在Worklet闭包中捕获大型数组/对象——它们会被复制到UI线程。
- 使用从Worklets调用JS代码;使用
runOnJS(fn)(args)从JS调用Worklets。runOnUI(fn)(args)
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 on
skipEnteringExitingAnimationsfor initial render.Animated.FlatList - 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
调试清单
- Babel plugin is last in plugins array
- Metro cache cleared ()
--reset-cache - Native code rebuilt (/
pod install)gradlew clean - directive present in custom worklet functions
'worklet' - Hooks only at component top level (never in worklets)
- Shared values used for animation state
- wraps the app
GestureHandlerRootView - Animation functions assigned to (not called standalone)
.value - Previous animations cancelled before new ones
- Babel插件位于插件数组最后一位
- 已清除Metro缓存()
--reset-cache - 已重新构建原生代码(/
pod install)gradlew clean - 自定义Worklet函数包含指令
'worklet' - Hooks仅在组件顶层使用(绝不在Worklets中)
- 使用共享值存储动画状态
- 应用被包裹
GestureHandlerRootView - 动画函数被赋值给(而非直接调用)
.value - 开始新动画前已取消原有动画
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, modifiers (withDecay,withDelay,withRepeat,withSequence), easing functions, spring physics, callbacks.withClamp - Hooks & Utilities: All hooks (,
useSharedValue,useAnimatedStyle,useAnimatedProps,useDerivedValue,useAnimatedReaction,useAnimatedRef,useAnimatedScrollHandler,useScrollViewOffset,useAnimatedKeyboard,useAnimatedSensor), utility functions (useFrameCallback,runOnJS,runOnUI,cancelAnimation,interpolate,interpolateColor).clamp - Worklets Deep Dive: Threading model, directive rules, closure capture, custom runtimes, thread communication (
'worklet',runOnUI,runOnJS), scheduling, debugging worklets.runOnUISync - 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), common patterns (swipeable item, bottom sheet, pull-to-refresh, carousel, photo viewer).Race - 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)、调度、Worklets调试。runOnUISync - 布局动画:进入/退出动画(淡入、滑动、缩放、弹跳、翻转、旋转等)、布局过渡、关键帧动画、列表动画、共享元素过渡。
- 手势集成:所有手势类型(点击、拖动、捏合、旋转、甩动、长按)、手势配置、组合(、
Simultaneous、Exclusive)、常见模式(可滑动项、底部弹窗、下拉刷新、轮播、图片查看器)。Race - 最佳实践与性能优化:60fps性能原则、动画优化模式、需避免的反模式、调试策略、平台特定指南(Android/iOS)、内存管理、复杂动画模式。
- 故障排除:安装问题、构建错误、运行时错误、动画问题、手势问题、性能问题、平台特定问题、错误信息参考。