mediumReact Native#36

Animated.Value fade-in

Prompt

Create a fade-in animation using Animated API. A View should fade from opacity 0 to 1 over 500ms when the component mounts.

Solution

const opacity = useRef(new Animated.Value(0)).current
useEffect(() => {
  Animated.timing(opacity, { toValue: 1, duration: 500, useNativeDriver: true }).start()
}, [])
return <Animated.View style={{ opacity, width: 200, height: 200, backgroundColor: 'blue' }} />
Mentor's take

The Animated API's core idea is animating outside the render cycle: Animated.Value is a mutable container that Animated.View writes to the native view directly — sixty opacity updates without a single React re-render. Re-rendering per frame through setState would be the naive alternative, and it's unshippable.

useRef(new Animated.Value(0)).current is deliberate: the value must survive re-renders. A plain const opacity = new Animated.Value(0) in the component body creates a fresh value on every render, visibly restarting the animation — the classic bug this pattern prevents.

useNativeDriver: true is the line the interview is about, and precision matters: it does not make the animation faster. Without it, every frame is computed in JS and sent across to native — so any JS-thread work (a render, a JSON parse, a navigation transition) starves the ticks and frames drop. With it, the full animation description — curve, duration, target — is serialized to the native side once at .start(), and the UI thread drives every frame independently. The win is decoupling: a blocked JS thread can no longer drop your frames. The price of that decoupling: the native driver only supports non-layout props — transform and opacity. Animating width or left natively throws at runtime; those need LayoutAnimation or Reanimated.

Red flag: "useNativeDriver makes animations faster." Per-frame cost is the same — it decouples the animation from the JS thread. Saying "faster" instead of "decoupled" is the junior tell.

Say it: "useNativeDriver serializes the animation to the UI thread once so JS-thread stalls can't drop frames — I default to it and accept its transform-and-opacity limit."