Reanimated 및 공유 값 설치
react-native-reanimated를 설치하고 Babel 플러그인을 추가한 다음, useSharedValue로 공유 값을 만들고 useAnimatedStyle을 사용하여 애니메이션 스타일에 연결합니다.
Reanimated 및 공유 값 설치은(는) CoddyKit의 무료 React Native Academy 강의입니다. 이것은 4개 중 1번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 React Native Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. React Native Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.
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.
자주 묻는 질문
“Reanimated 및 공유 값 설치” 강의는 무료인가요?
네 — “Reanimated 및 공유 값 설치” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 React Native Academy 강의 전체를 잠금 해제할 수 있습니다. React Native Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“Reanimated 및 공유 값 설치”에서 뭘 배우나요?
react-native-reanimated를 설치하고 Babel 플러그인을 추가한 다음, useSharedValue로 공유 값을 만들고 useAnimatedStyle을 사용하여 애니메이션 스타일에 연결합니다. 브라우저에서 직접 실행하는 실습 코드로 React Native Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
React Native Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 React Native Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 1번째 강의입니다.
“Reanimated 및 공유 값 설치” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 React Native Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 React Native Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- Reanimated 및 공유 값 설치
- Worklet과 UI 스레드에서 코드 실행하기
- Gesture Handler로 팬 및 스와이프 제스처 구현하기
- 핀치 확대 및 회전