Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Animation basics

An animation is a smooth change of a style over time: opacity, position, size. On a phone it shows what happened: a new task smoothly appeared, a deleted one faded out. React Native has the built-in Animated module, and for complex cases, the Reanimated library.

Animated: fading in

Let us make a wrapper that fades its content in over 400 milliseconds:

// components/FadeIn.tsx
import { type ReactNode, useEffect, useRef } from 'react';
import { Animated } from 'react-native';
 
export default function FadeIn({ children }: { children: ReactNode }) {
  const opacity = useRef(new Animated.Value(0)).current;
 
  useEffect(() => {
    Animated.timing(opacity, {
      toValue: 1,
      duration: 400,
      useNativeDriver: true,
    }).start();
  }, [opacity]);
 
  return <Animated.View style={{ opacity }}>{children}</Animated.View>;
}

How it works:

  1. Animated.Value(0) is an animatable number with an initial opacity of 0. useRef keeps it between renders.
  2. Animated.View is a View that understands such values in style.
  3. Animated.timing changes the value to toValue over duration milliseconds, and start() runs the animation.
  4. useNativeDriver: true hands the animation to native code, so it stays smooth even when JavaScript is busy.

Using it

Wrap the task row in the list's renderItem:

// app/index.tsx
import FadeIn from '@/components/FadeIn';
 
renderItem={({ item }) => (
  <FadeIn>
    <TaskItem task={item} onToggle={toggleTask} />
  </FadeIn>
)}

Add a task: it does not pop up abruptly but fades in. Tasks already on the screen do not flicker, because the animation runs only when a component is shown for the first time.

What useNativeDriver can animate

YesNo
opacitywidth, height
transform: move, scale, rotatebackgroundColor
margin, padding

For layout properties useNativeDriver is set to false, but such an animation is less smooth.

Reanimated

The react-native-reanimated library is already installed in the Expo template. It runs animations entirely on the native thread and offers ready-made enter and exit animations:

// components/TaskItem.tsx
import Animated, { FadeIn, FadeOut } from 'react-native-reanimated';
 
<Animated.View entering={FadeIn} exiting={FadeOut}>
  <Text>{task.title}</Text>
</Animated.View>

With entering and exiting, a task fades in when added and fades out when deleted, without manual values or effects. For manually controlled animations, Reanimated has the useSharedValue and useAnimatedStyle hooks and the withTiming function.

Common mistake

Creating an Animated.Value right in the component body: const opacity = new Animated.Value(0);. Every render creates a new value equal to zero, and the animation resets or does not run at all. Keep it in useRef, as in the example.

Thanks for reading!

Donate to the site — we work hard for you.