Adopting Reanimated 2 in React Native: Move Animations to the UI Thread for 60 fps
Reanimated 2 moves animation logic to the UI thread, enabling 60 fps in React Native. This guide shows how to install, configure, and use a minimal draggable square example, then verifies performance and highlights common mistakes.
13 Mar 2026, 02:51 UTC

Why Reanimated 2?
React Native’s built‑in Animated API runs on the JavaScript thread. When complex gestures or physics calculations are involved, the JS thread can become a bottleneck, causing frame drops and a janky user experience. Reanimated 2 solves this by moving animation logic to the native UI thread through worklets. Worklets are small, pure JavaScript functions that are serialized and executed on the UI thread, eliminating the JS‑to‑UI bridge round‑trip for every frame.
Setting Up Reanimated 2
Install the library in your project (replace
latestwith a specific version if you prefer):cd <your-project> npm install react-native-reanimated@latestConfigure Babel by adding the Reanimated plugin. Edit
babel.config.js:
This plugin rewrites worklet functions so they can run on the UI thread.module.exports = { presets: ['module:metro-react-native-babel-preset'], plugins: ['react-native-reanimated/plugin'], };Rebuild the app to link native modules. On iOS use
xcodebuildor open the workspace; on Android usegradlew assembleDebug. No additional native code changes are required for Reanimated 2.
Minimal Working Example: Draggable Square
The following component demonstrates a square that the user can drag across the screen. The position is stored in a sharedValue and updated by a worklet. The useAnimatedStyle hook applies the animated style to the view.
import React from 'react';
import {StyleSheet, View} from 'react-native';
import Animated, {
useSharedValue,
useAnimatedStyle,
withSpring,
PanGestureHandler,
GestureHandlerRootView,
} from 'react-native-reanimated';
export default function DraggableSquare() {
const translateX = useSharedValue(0);
const translateY = useSharedValue(0);
const animatedStyle = useAnimatedStyle(() => {
return {
transform: [
{translateX: translateX.value},
{translateY: translateY.value},
],
};
});
const onGesture = ({nativeEvent}) => {
translateX.value = nativeEvent.translationX;
translateY.value = nativeEvent.translationY;
};
return (
);
}
const styles = StyleSheet.create({
container: {flex: 1, justifyContent: 'center', alignItems: 'center'},
box: {width: 100, height: 100, backgroundColor: 'tomato'},
});
Key points:
translateXandtranslateYaresharedValueobjects that live on the UI thread.- The
onGesturehandler is a worklet (identified by thenativeEventargument) and runs on the UI thread. - Because all heavy lifting is off the JS thread, the UI stays at 60 fps even when the gesture logic is complex.
Verifying Performance
To confirm that Reanimated 2 is working as intended, follow these steps:
Run the app on a real device or emulator. Use
adb logcat(Android) or Xcode console (iOS) to watch for any runtime errors.Open the Android Studio Profiler or Xcode Instruments and monitor the CPU and Frames per Second (FPS) metrics while dragging the square. You should see the JS thread idle and the UI thread handling the animation frames.
Look for the console warning
Reanimated: Worklet is not pure. If present, it means a worklet accessed external state or performed a side‑effect. Refactor the worklet to be pure or userunOnJSto call JS code from the UI thread.
Common Mistakes & Limits
- Missing Babel Plugin: Without
'react-native-reanimated/plugin'inbabel.config.js, Reanimated works but throwsAnimated: Unable to find a native componentat runtime. Always rebuild after adding the plugin. - Mixing APIs: Using Reanimated worklets alongside the standard
AnimatedAPI can cause frame drops because both threads compete for native resources. Stick to one API per component tree. - Non‑pure Worklets: Worklets must be pure functions with no side‑effects and no access to component state. If you need to update JS state from a worklet, use
runOnJS. - Platform Limits: Reanimated 2 does not support the Web target. Minimum native SDKs are iOS >= 11 and Android >= 6.
- Debug Builds: In debug mode, Reanimated may run slower because worklets are not fully optimized. Test on a release build for accurate performance.
Conclusion
Adopting Reanimated 2 gives React Native projects a robust, native‑thread animation engine that keeps the UI smooth even under heavy gesture or physics workloads. The setup is straightforward—install, add the Babel plugin, rebuild, and replace the Animated hooks with Reanimated’s equivalents. By following the verification steps and avoiding the common pitfalls, you can confidently deliver high‑performance animations that feel native.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.