Skip to main content

Reanimated

Reanimated is the standard animation library for React Native. Animation logic runs on the UI thread as worklets: small JS functions that the Babel plugin copies into a second JS runtime living on the UI thread. State lives in shared values (useSharedValue), readable and writable from both threads; useAnimatedStyle turns them into styles that are applied to the view on every frame without React re-renders and without the JS thread. Version 4 adds CSS-like animations and transitions and works only on the New Architecture.

Applies to: Reanimated 4, React Native 0.88.

Details​

Core API​

APIWhat it does
useSharedValue(initial)A value shared by JS and UI threads; read and write with .value, or .get() / .set() (recommended with React Compiler)
useAnimatedStyle(() => style)A worklet that computes a style from shared values; re-runs when they change
useDerivedValue(() => value)A shared value computed from others, like useMemo on the UI thread
useAnimatedPropsSame as useAnimatedStyle for non-style props (SVG d, TextInput text)
useAnimatedScrollHandlerHandles scroll events on the UI thread
withTiming, withSpring, withDecayAnimate a shared value to a target: x.value = withSpring(100)
withSequence, withRepeat, withDelayCompose animations
interpolate, interpolateColorMap a value from one range to another
cancelAnimation(sv)Stop an animation on a shared value

Threads and Worklets​

  • A function becomes a worklet with the 'worklet' directive; callbacks of useAnimatedStyle, useDerivedValue and gesture callbacks are workletized automatically by the Babel plugin.
  • A worklet captures the variables it uses by copy; it cannot touch React state or call ordinary JS functions directly.
  • To call a JS-thread function from a worklet (set state, log analytics), use scheduleOnRN(fn, ...args) from react-native-worklets (formerly runOnJS(fn)(...args)). To run a worklet on the UI thread from JS, use scheduleOnUI (formerly runOnUI).
  • Reading .value on the JS thread is synchronous and can block; do not read shared values during render.

Layout and CSS Animations​

FeatureHow
Entering / exiting<Animated.View entering={FadeIn} exiting={FadeOut} />: animates mount and unmount
Layout transitionslayout={LinearTransition}: animates position and size changes after a re-render
CSS transitionstransitionProperty, transitionDuration in the style: a change of that style prop animates (new in 4)
CSS animationsanimationName with keyframes, animationDuration, animationIterationCount (new in 4)

CSS transitions and animations are the simplest choice for state-driven animations; shared values are for gestures, scroll and anything interactive.

Why Reanimated Is Faster than Animated​

AnimatedReanimated
Native driver: non-layout props only (layout props with the experimental backend since 0.85), fixed animationsAny style property on the UI thread
Logic (gesture → value) runs in JSLogic is a worklet on the UI thread; JS can be busy
Layout properties need JS on every frameLayout properties are animated without JS

Version History​

VersionWhat changed
1Declarative "nodes" API; removed
2, 3Shared values, worklets, hooks, layout animations
4New Architecture only; worklets moved to react-native-worklets; CSS animations and transitions

Example​

import { useState } from 'react';
import { Pressable, Text } from 'react-native';
import Animated, {
FadeIn,
useAnimatedStyle,
useSharedValue,
withSequence,
withSpring,
withTiming,
} from 'react-native-reanimated';
import { scheduleOnRN } from 'react-native-worklets';

export function LikeButton({ onBounceEnd }: { onBounceEnd: () => void }) {
const [likes, setLikes] = useState(0);
const scale = useSharedValue(1);

const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scale: scale.value }],
}));

const onPress = () => {
setLikes((count) => count + 1); // onPress runs on the JS thread
scale.value = withSequence(
withTiming(1.3, { duration: 100 }),
withSpring(1, {}, (finished) => {
// The callback is a worklet on the UI thread: go back to JS
if (finished) scheduleOnRN(onBounceEnd);
})
);
};

return (
<Pressable onPress={onPress}>
<Animated.View entering={FadeIn} style={animatedStyle}>
<Text>♥ {likes}</Text>
</Animated.View>
</Pressable>
);
}
CSS transition
import Animated from 'react-native-reanimated';

export function Panel({ open }: { open: boolean }) {
return (
<Animated.View
style={{
height: open ? 200 : 0,
transitionProperty: 'height',
transitionDuration: 300,
}}
/>
);
}

Follow-up Questions​

  • How do you react to a shared value without a style? useAnimatedReaction.
  • Does a worklet see the latest React state? Only the copy from the render that created it: useAnimatedStyle picks up new state after a re-render, but a running gesture or animation callback keeps the old copy; put changing data in a shared value.
  • Which Babel plugin is needed? react-native-worklets/plugin.
  • Does Reanimated respect Reduce Motion? Yes: animations default to ReduceMotion.System and finish at once when the setting is on, see Accessibility.

Common Mistakes​

  • Describing Reanimated 1: "nodes" and Transitioning no longer exist.
  • Mentioning useNativeDriver with Reanimated: it is an Animated option.
  • Calling a regular JS function or setState directly inside a worklet: it crashes; wrap it in scheduleOnRN.
  • Setting React state on every frame of a gesture instead of a shared value.

See Also​