Installing Reanimated and Shared Values
Install react-native-reanimated, add the Babel plugin, create shared values with useSharedValue, and connect them to animated styles using useAnimatedStyle.
Installing Reanimated and Shared Values is a free React Native Academy lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the React Native Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Why Reanimated Exists
React Native Reanimated is a more powerful animation library that goes beyond what the built-in Animated API can achieve. While the Animated API moves animation config to native once and runs it there, Reanimated lets you run arbitrary JavaScript-like logic — called worklets — directly on the UI thread, frame by frame.
This enables gesture-driven animations where the animation responds in real time to finger position, impossible with the Animated API's pre-configured approach. Reanimated 3 is the current version and is the foundation of React Native Gesture Handler's smooth interactions.
Installing react-native-reanimated
Install Reanimated from npm, then add the Babel plugin to babel.config.js. The Babel plugin transforms worklet functions at build time so they can run on the UI thread. Without the plugin the library will silently fail at runtime.
For Expo managed workflow, the library must be compatible with your SDK version. Check the Reanimated compatibility table before installing. After installation you must rebuild the native app — Reanimated cannot be added via OTA update.
// Terminal:
// npx expo install react-native-reanimated
// babel.config.js:
module.exports = {
presets: ['babel-preset-expo'],
plugins: ['react-native-reanimated/plugin'],
};
// IMPORTANT: Reanimated plugin must be listed LASTuseSharedValue: The Reanimated Primitive
useSharedValue is Reanimated's equivalent of Animated.Value. It creates a value that is shared between the JavaScript thread and the UI thread, and can be read and written from worklets running on the UI thread without crossing the bridge.
Unlike useState, writing to a shared value does NOT trigger a React re-render. Instead, it directly updates the animated style on the UI thread. This is what enables smooth gesture tracking — updating position 60+ times per second without React involvement.
import { useSharedValue } from 'react-native-reanimated';
import { useEffect } from 'react';
export default function MyComponent() {
const offset = useSharedValue(0);
const opacity = useSharedValue(1);
// Read the value: offset.value
// Write to it: offset.value = 100
}useAnimatedStyle: Connecting Values to Styles
useAnimatedStyle creates a style object that is recalculated on the UI thread whenever any shared value it reads changes. You pass a worklet function that returns a style object, reading shared values with .value. Connect the returned style to a ReanimatedView (imported as Animated.View from Reanimated).
This is the bridge between shared values and the visible UI. The style function runs on the UI thread, so it has zero impact on React rendering or the JavaScript thread.
import Animated, { useSharedValue, useAnimatedStyle } from 'react-native-reanimated';
export default function Box() {
const offset = useSharedValue(0);
const animatedStyles = useAnimatedStyle(() => ({
transform: [{ translateX: offset.value }],
}));
return <Animated.View style={[styles.box, animatedStyles]} />;
}withTiming and withSpring Animations
Instead of calling Animated.timing on a shared value, you assign it the return value of withTiming or withSpring. These are animation functions that drive the shared value toward a target value over time, evaluated on the UI thread.
Assigning offset.value = withTiming(100) starts a smooth timing animation. Assigning offset.value = withSpring(100) starts a spring. This assignment syntax is simpler than the Animated API's imperative .start() pattern.
import { useSharedValue, withTiming, withSpring } from 'react-native-reanimated';
const offset = useSharedValue(0);
// Trigger a timing animation:
function moveRight() {
offset.value = withTiming(200, { duration: 500 });
}
// Trigger a spring:
function springRight() {
offset.value = withSpring(200, { damping: 15, stiffness: 100 });
}Animating Opacity and Scale
Opacity and scale shared values work exactly the same way — create a shared value, build an animated style with useAnimatedStyle, and assign animation functions to the value to trigger transitions. Multiple shared values can be combined in a single useAnimatedStyle.
The key advantage over the Animated API is that the worklet function in useAnimatedStyle runs inline with gesture events on the UI thread, enabling perfectly smooth real-time tracking.
const scale = useSharedValue(1);
const opacity = useSharedValue(0);
const style = useAnimatedStyle(() => ({
opacity: opacity.value,
transform: [{ scale: scale.value }],
}));
// Animate on press:
function press() {
scale.value = withSpring(0.9);
opacity.value = withTiming(0.7, { duration: 150 });
}
function release() {
scale.value = withSpring(1);
opacity.value = withTiming(1, { duration: 150 });
}useAnimatedStyle Worklet Rules
The function passed to useAnimatedStyle is a worklet — it runs on the UI thread, not the JavaScript thread. This means it cannot access JavaScript closures, imported modules, or React state directly. It can only access shared values and primitive constants captured at definition time.
Reanimated's Babel plugin transforms the worklet function to make it UI-thread safe. If you violate these rules, you will see cryptic runtime errors. When in doubt, test with a simple transformation before adding complexity.
const offset = useSharedValue(0);
const MULTIPLIER = 2; // primitives captured OK
// CORRECT: only reads sharedValue and primitive
const style = useAnimatedStyle(() => ({
transform: [{ translateX: offset.value * MULTIPLIER }],
}));
// WRONG: accessing React state would throw
// const [reactState] = useState(0);
// const badStyle = useAnimatedStyle(() => ({
// opacity: reactState, // cannot read React state in worklet
// }));Running Reanimated with Expo Go
Reanimated requires the native module to be compiled into the app binary. In Expo managed workflow, this means you need a development build (created with npx expo run:android or npx expo run:ios) rather than the standard Expo Go app, which does not include Reanimated's native module.
An easy alternative is using Expo's development client (expo-dev-client), which is a customizable Expo Go that includes your own native modules. Install it, rebuild, and scan the QR code to get a development environment that supports Reanimated.
// Install expo-dev-client for Reanimated support:
// npx expo install expo-dev-client
// npx expo run:ios (or run:android)
// Then in babel.config.js ensure:
module.exports = {
presets: ['babel-preset-expo'],
plugins: ['react-native-reanimated/plugin'], // must be last
};Chaining Animations with withSequence
Reanimated provides withSequence and withRepeat to compose animations directly in the value assignment, without the separate Animated.sequence or Animated.loop objects. The syntax is more concise and functional.
withRepeat accepts an animation, a repeat count (−1 for infinite), and a boolean to reverse direction. withSequence chains multiple animation phases in order.
import { withTiming, withSpring, withSequence, withRepeat } from 'react-native-reanimated';
// Shake animation: left, right, center
offset.value = withSequence(
withTiming(-10, { duration: 100 }),
withTiming(10, { duration: 100 }),
withTiming(0, { duration: 100 })
);
// Pulse animation (infinite):
opacity.value = withRepeat(
withTiming(0.3, { duration: 600 }),
-1, // repeat forever
true // reverse each cycle
);Reading Shared Values vs React State
An important mental model: shared values are not React state. Writing to offset.value does not cause a re-render. The UI updates via animated styles directly. If you need to synchronize a shared value with React state (e.g., to render conditional JSX), use useAnimatedReaction or runOnJS to call a React state setter from the UI thread.
Understanding this boundary — Reanimated lives outside React's render cycle — is the key to using it effectively without introducing bugs.
import { useAnimatedReaction, runOnJS } from 'react-native-reanimated';
const [isVisible, setIsVisible] = React.useState(true);
const opacity = useSharedValue(1);
// React to shared value changes on JS thread:
useAnimatedReaction(
() => opacity.value,
(current) => {
if (current === 0) runOnJS(setIsVisible)(false);
}
);Reanimated vs Animated API Summary
When to use each animation system:
- Animated API — Simple entrance/exit animations, opacity fades, pre-configured sequences. Lower learning curve, ships with React Native, sufficient for most apps.
- Reanimated — Gesture-responsive animations, real-time tracking, complex interactive physics. Required when animation must respond to live gesture position frame by frame.
Many production apps use Animated API for simple UI transitions and Reanimated only for gesture-driven components like swipeable cards, bottom sheets, and drag-and-drop.
Quick Check
Test your understanding of React Native Mobile Development concepts from this lesson.
Lesson Recap
In this lesson you learned: useSharedValue creates a value shared between the JS and UI threads for zero-bridge-overhead animations, useAnimatedStyle connects shared values to component styles via a UI-thread worklet, and withTiming and withSpring are assigned to sharedValue.value to start animations. Next up we explore worklets and how they enable complex gesture logic running entirely on the UI thread.
Frequently asked questions
Is the “Installing Reanimated and Shared Values” lesson free?
Yes — the full text of “Installing Reanimated and Shared Values” is free to read here on the web, and the React Native Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the React Native Academy course, upgrade to CoddyKit PRO.
What will I learn in “Installing Reanimated and Shared Values”?
Install react-native-reanimated, add the Babel plugin, create shared values with useSharedValue, and connect them to animated styles using useAnimatedStyle. You practise React Native Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start React Native Academy?
No prior experience is required. React Native Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Installing Reanimated and Shared Values” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this React Native Academy lesson?
Yes. Every React Native Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Installing Reanimated and Shared Values
- Worklets and Running Code on the UI Thread
- Pan and Swipe Gestures with Gesture Handler
- Pinch-to-Zoom and Rotation