rn-reanimated

React Native Reanimated — Best Practices & 60fps Guide

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "rn-reanimated" with this command: npx skills add imfa-solutions/skills/imfa-solutions-skills-rn-reanimated

React Native Reanimated — Best Practices & 60fps Guide

Reanimated 4.x / Worklets 0.7.x / React Native 0.80+ (New Architecture required)

Critical Rules

  • Babel plugin must be LAST in babel.config.js plugins array.

  • Never use React state (useState ) for values that drive animations. Use useSharedValue .

  • Never call withTiming /withSpring inside gesture .onUpdate callbacks. Assign the event value directly for smooth tracking; use spring/timing only in .onEnd .

  • Always cancel animations before starting new ones when gestures begin: cancelAnimation(sv) .

  • Always pass velocity from gesture events into withSpring for natural feel.

  • Always wrap the app in <GestureHandlerRootView style={{ flex: 1 }}> . Gestures won't work without it.

  • Always cancel animations on unmount via useEffect cleanup.

  • Respect reduced motion — use ReduceMotion.System or 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:

FileLineIssueSeverityFix
src/Card.tsx12useState driving animationHIGHReplace with useSharedValue
src/Sheet.tsx45Missing cancelAnimation in onBeginHIGHAdd cancelAnimation(sv)
src/List.tsx78Math.random() as keyMEDIUMUse 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")

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

Installation

npm install react-native-reanimated react-native-worklets react-native-gesture-handler

// 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 ).

Core Pattern — The Only Pattern You Need

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 withSpring

  • velocity Natural physics feel

Fixed-duration transition withTiming (200-500ms) Predictable timing

Momentum/fling withDecay

Natural deceleration

Toggle state withSpring

Bouncy feedback

Spring Presets

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 };

Gesture Pattern (Pan with Spring Back)

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 }); });

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

Anti-Patterns to Fix on Sight

Anti-Pattern Fix

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 gesture Add { velocity: event.velocityX }

Shadow animation on Android Use 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)

Platform-Specific Rules

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.

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).

Memory Management

useEffect(() => { return () => { cancelAnimation(offset); cancelAnimation(scale); }; }, []);

For reactions that call runOnJS , guard with a mounted flag:

const isMounted = useSharedValue(true); useEffect(() => () => { isMounted.value = false; }, []);

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

Worklet Rules

  • '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.

Layout Animations Quick Reference

<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} .

Debugging Checklist

  • Babel plugin is last in plugins array

  • Metro cache cleared (--reset-cache )

  • Native code rebuilt (pod install / gradlew clean )

  • 'worklet' directive present in custom worklet functions

  • Hooks only at component top level (never in worklets)

  • Shared values used for animation state

  • GestureHandlerRootView wraps the app

  • Animation functions assigned to .value (not called standalone)

  • Previous animations cancelled before new ones

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.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

rn-skia

No summary provided by upstream source.

Repository SourceNeeds Review
General

convex-file-system

No summary provided by upstream source.

Repository SourceNeeds Review
General

rn-heroui

No summary provided by upstream source.

Repository SourceNeeds Review
General

convex-rate-limiter

No summary provided by upstream source.

Repository SourceNeeds Review