rn-reanimated
9
总安装量
9
周安装量
#31931
全站排名
安装命令
npx skills add https://github.com/imfa-solutions/skills --skill rn-reanimated
Agent 安装分布
gemini-cli
9
antigravity
9
claude-code
9
github-copilot
9
codex
9
kimi-cli
9
Skill 文档
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.jsplugins array. - Never use React state (
useState) for values that drive animations. UseuseSharedValue. - Never call
withTiming/withSpringinside gesture.onUpdatecallbacks. 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
velocityfrom gesture events intowithSpringfor natural feel. - Always wrap the app in
<GestureHandlerRootView style={{ flex: 1 }}>. Gestures won’t work without it. - Always cancel animations on unmount via
useEffectcleanup. - Respect reduced motion â use
ReduceMotion.SystemoruseReducedMotion().
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”)
What to Check (scan checklist)
-
useState/setStateused for values that drive animations â replace withuseSharedValue -
withTiming/withSpringcalled inside gesture.onUpdateâ replace with direct assignment -
.valueread directly in JSX render â wrap inuseAnimatedStyle - Animation created in render return â move to handler/effect
- Missing
cancelAnimationin gesture.onBeginâ add it - Missing
velocityinwithSpringafter 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
GestureHandlerRootViewwrapping the app - Missing animation cleanup in
useEffectreturn - Missing mounted guard for
runOnJSinuseAnimatedReaction -
'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,shadowRadiuson Android - Missing
overflow: 'hidden'forborderRadiusanimation on Android - No reduced motion handling (
ReduceMotion.SystemoruseReducedMotion()) -
Animated.FlatListmissingskipEnteringExitingAnimationsfor 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
elevationinstead of shadow properties for animated shadows. - Use
overflow: 'hidden'on parent for smoothborderRadiusanimation. - 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
localStorageinside worklets. - Never close over large arrays/objects â they get copied to the UI thread.
- Use
runOnJS(fn)(args)to call JS from worklets; userunOnUI(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
skipEnteringExitingAnimationsonAnimated.FlatListfor 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
GestureHandlerRootViewwraps 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.