Skip to main content
useAnimatedValue is a React hook that creates a persistent Animated.Value instance. The animated value is created only once and persists across component re-renders, making it ideal for animations in functional components.

Signature

function useAnimatedValue(
  initialValue: number,
  config?: AnimatedConfig
): Animated.Value

Parameters

  • initialValue - The initial numeric value for the animated value
  • config (optional) - Configuration options for the animated value
    • useNativeDriver?: boolean - Whether to use the native driver for animations

Returns

An Animated.Value instance that persists across re-renders.

Usage

import { useAnimatedValue } from 'react-native';
import { View, Animated, Button } from 'react-native';

function FadeInView() {
  const opacity = useAnimatedValue(0);

  const fadeIn = () => {
    Animated.timing(opacity, {
      toValue: 1,
      duration: 500,
      useNativeDriver: true,
    }).start();
  };

  return (
    <View>
      <Animated.View style={{ opacity }}>
        <Text>Fading in!</Text>
      </Animated.View>
      <Button title="Fade In" onPress={fadeIn} />
    </View>
  );
}

Common Patterns

Fade Animation

import { useAnimatedValue } from 'react-native';
import { useEffect } from 'react';
import { Animated, View, Text } from 'react-native';

function AutoFadeIn({ children }: { children: React.ReactNode }) {
  const opacity = useAnimatedValue(0);

  useEffect(() => {
    Animated.timing(opacity, {
      toValue: 1,
      duration: 300,
      useNativeDriver: true,
    }).start();
  }, []);

  return (
    <Animated.View style={{ opacity }}>
      {children}
    </Animated.View>
  );
}

Scale Animation

import { useAnimatedValue } from 'react-native';
import { Pressable, Animated } from 'react-native';

function ScaleButton({ onPress, children }: { onPress: () => void; children: React.ReactNode }) {
  const scale = useAnimatedValue(1);

  const handlePressIn = () => {
    Animated.spring(scale, {
      toValue: 0.95,
      useNativeDriver: true,
    }).start();
  };

  const handlePressOut = () => {
    Animated.spring(scale, {
      toValue: 1,
      friction: 3,
      tension: 40,
      useNativeDriver: true,
    }).start();
  };

  return (
    <Pressable onPressIn={handlePressIn} onPressOut={handlePressOut} onPress={onPress}>
      <Animated.View style={{ transform: [{ scale }] }}>
        {children}
      </Animated.View>
    </Pressable>
  );
}

Slide Animation

import { useAnimatedValue } from 'react-native';
import { useEffect } from 'react';
import { Animated, Dimensions } from 'react-native';

function SlideInView({ children }: { children: React.ReactNode }) {
  const slideAnim = useAnimatedValue(-Dimensions.get('window').width);

  useEffect(() => {
    Animated.spring(slideAnim, {
      toValue: 0,
      bounciness: 8,
      useNativeDriver: true,
    }).start();
  }, []);

  return (
    <Animated.View
      style={{
        transform: [{ translateX: slideAnim }],
      }}
    >
      {children}
    </Animated.View>
  );
}

Progress Bar

import { useAnimatedValue } from 'react-native';
import { useEffect } from 'react';
import { Animated, View, StyleSheet } from 'react-native';

function ProgressBar({ progress }: { progress: number }) {
  const animatedProgress = useAnimatedValue(0);

  useEffect(() => {
    Animated.timing(animatedProgress, {
      toValue: progress,
      duration: 500,
      useNativeDriver: false, // width animations don't support native driver
    }).start();
  }, [progress]);

  const width = animatedProgress.interpolate({
    inputRange: [0, 100],
    outputRange: ['0%', '100%'],
  });

  return (
    <View style={styles.progressBarContainer}>
      <Animated.View style={[styles.progressBar, { width }]} />
    </View>
  );
}

const styles = StyleSheet.create({
  progressBarContainer: {
    height: 8,
    backgroundColor: '#e0e0e0',
    borderRadius: 4,
    overflow: 'hidden',
  },
  progressBar: {
    height: '100%',
    backgroundColor: '#4caf50',
  },
});

Rotate Animation

import { useAnimatedValue } from 'react-native';
import { useEffect } from 'react';
import { Animated, Easing } from 'react-native';

function SpinningLoader() {
  const rotation = useAnimatedValue(0);

  useEffect(() => {
    Animated.loop(
      Animated.timing(rotation, {
        toValue: 1,
        duration: 1000,
        easing: Easing.linear,
        useNativeDriver: true,
      })
    ).start();
  }, []);

  const rotate = rotation.interpolate({
    inputRange: [0, 1],
    outputRange: ['0deg', '360deg'],
  });

  return (
    <Animated.View
      style={{
        width: 50,
        height: 50,
        transform: [{ rotate }],
      }}
    >
      {/* Loader icon */}
    </Animated.View>
  );
}

Color Animation

import { useAnimatedValue } from 'react-native';
import { Pressable, Animated } from 'react-native';

function AnimatedButton({ children }: { children: React.ReactNode }) {
  const colorAnim = useAnimatedValue(0);

  const handlePressIn = () => {
    Animated.timing(colorAnim, {
      toValue: 1,
      duration: 200,
      useNativeDriver: false,
    }).start();
  };

  const handlePressOut = () => {
    Animated.timing(colorAnim, {
      toValue: 0,
      duration: 200,
      useNativeDriver: false,
    }).start();
  };

  const backgroundColor = colorAnim.interpolate({
    inputRange: [0, 1],
    outputRange: ['#2196f3', '#1976d2'],
  });

  return (
    <Pressable onPressIn={handlePressIn} onPressOut={handlePressOut}>
      <Animated.View
        style={{
          backgroundColor,
          padding: 16,
          borderRadius: 8,
        }}
      >
        {children}
      </Animated.View>
    </Pressable>
  );
}

When to Use

Use useAnimatedValue when you need:
  • A single numeric animated value in a functional component
  • To animate properties like opacity, scale, rotation, or position
  • A persistent animation value that survives re-renders

Alternatives

  • useAnimatedValueXY - For animating 2D positions (x, y coordinates)
  • new Animated.Value() - Class component equivalent (requires manual ref management in functional components)
  • Reanimated library - For more complex animations with better performance

Implementation Details

This hook:
  • Uses useRef to store the Animated.Value instance
  • Creates the animated value only once on first render
  • Returns the same instance on subsequent re-renders
  • The initial value is only used during the first render
// Simplified implementation
function useAnimatedValue(initialValue: number, config?: AnimatedConfig) {
  const ref = useRef<Animated.Value | null>(null);
  if (ref.current == null) {
    ref.current = new Animated.Value(initialValue, config);
  }
  return ref.current;
}

Performance Tips

  • Always use useNativeDriver: true when possible for better performance
  • Native driver supports: transform and opacity
  • Native driver does NOT support: layout properties (width, height, etc.) and backgroundColor
  • Animations run on the native thread, avoiding JavaScript thread blocking

See Also

Build docs developers (and LLMs) love