Q&A
How to add element transitions in React Native
Overview
"Transitions" in React Native typically means animating a visual change: sliding, fading, scaling when a component appears/disappears, or reacting to user input. You choose your tool by complexity: Animated for custom programmatic control, LayoutAnimation for automatic layout changes, Reanimated for advanced/gesture work, or a library for quick declarative animations.
graph TD
A[Element transition needed] --> B[Simple / custom: Animated API]
A --> C[Layout change: LayoutAnimation]
A --> D[Complex / gesture / UI thread: Reanimated]
A --> E[Quick declarative: react-native-animatable]
style D fill:#1e1b4b,color:#fff
Option 1: Animated API (built-in)
The Animated API lets you programmatically animate values and connect them to styles.
Fade-in on mount
import { useRef, useEffect } from "react";
import { Animated, View } from "react-native";
function FadeIn({ children }) {
const opacity = useRef(new Animated.Value(0)).current;
useEffect(() => {
Animated.timing(opacity, {
toValue: 1,
duration: 500,
useNativeDriver: true, // runs on UI thread - always enable if possible
}).start();
}, []);
return <Animated.View style={{ opacity }}>{children}</Animated.View>;
}
Slide in from right
const translateX = useRef(new Animated.Value(300)).current; // start off-screen
useEffect(() => {
Animated.spring(translateX, {
toValue: 0,
useNativeDriver: true,
}).start();
}, []);
<Animated.View style={{ transform: [{ translateX }] }}>
{children}
</Animated.View>
useNativeDriver: true is critical - it runs the animation on the UI thread, giving 60fps even when JS is busy. It works for opacity and transform; it does NOT work for width, height, or other layout properties (those require Reanimated or LayoutAnimation).
Option 2: LayoutAnimation (automatic layout transitions)
When you change state and the layout shifts, LayoutAnimation automatically animates the change:
import { LayoutAnimation, Platform, UIManager } from "react-native";
// Android needs this enabled explicitly:
if (Platform.OS === "android") {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
function toggleExpand() {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
setExpanded(!expanded); // state change → layout change is animated
}
Simple but limited - no fine control over individual properties.
Option 3: React Native Reanimated (UI-thread, best performance)
For gesture-driven transitions and complex sequences, Reanimated runs animations natively (see answer 072):
import Animated, { useSharedValue, useAnimatedStyle, withTiming } from "react-native-reanimated";
const translateY = useSharedValue(-100);
const style = useAnimatedStyle(() => ({ transform: [{ translateY: translateY.value }] }));
// trigger:
translateY.value = withTiming(0, { duration: 400 });
Option 4: react-native-animatable (declarative, CSS-style)
npm install react-native-animatable
import * as Animatable from "react-native-animatable";
<Animatable.View animation="fadeInUp" duration={600} delay={200}>
<Text>Hello!</Text>
</Animatable.View>
Pre-built named animations (fadeIn, slideInRight, bounceIn, zoomOut, shake, etc.) work like CSS animation classes - no manual Animated.Value management.
Combining with Navigation Transitions
For page/screen transitions, React Navigation lets you customise transitionSpec and cardStyleInterpolator per stack, or choose presets (SlideFromRightIOS, ModalSlideFromBottomIOS, FadeFromBottomAndroid, etc.). The navigation library handles the transition; you just pick the preset.
Choosing the Right Tool
| Need | Use |
|---|---|
| Custom programmatic animation | Animated API + useNativeDriver: true |
| Layout changes (height, position) | LayoutAnimation |
| Gesture-driven / complex / performance-critical | React Native Reanimated |
| Quick named CSS-like animations | react-native-animatable |
| Screen transitions | React Navigation presets |
Why This Matters in Interviews
React Native interviews use this to check animation fundamentals and performance awareness. Key points: useNativeDriver: true to keep animations on the UI thread (works for opacity/transform); LayoutAnimation for automatic layout-change transitions; Reanimated for anything gesture-driven or where JS-thread jank is a concern; and react-native-animatable for quick declarative effects. Explaining why useNativeDriver matters (avoids JS-thread bottleneck) is the performance signal.
Common Pitfalls
- Forgetting
useNativeDriver: true- animation runs on the JS thread and stutters under load. - Using
Animatedfor layout properties (width,height) withuseNativeDriver: true- this combination doesn't work; use Reanimated or LayoutAnimation instead. - Creating
new Animated.Value(...)inside render (creates a new value every render) - useuseRef. - Not enabling
setLayoutAnimationEnabledExperimentalon Android for LayoutAnimation. - Expecting
react-native-animatableto have gesture-responsiveness (it's declarative, not interactive).
References
- React Native Animated: https://reactnative.dev/docs/animations
- React Native LayoutAnimation: https://reactnative.dev/docs/layoutanimation
- Reanimated: https://docs.swmansion.com/react-native-reanimated/