rn-prefer-reanimated: native-driver opacity animation reported as JS-thread animation

Author: thomasorgevalCreated Sep 10, 2026Updated Sep 10, 2026

The rule reports the Animated import as a JS-thread animation even though the only animation explicitly uses useNativeDriver: true and only animates opacity.

Reproduction

Reproduced with React Doctor 0.9.13, Node 24.18.0, on macOS. JSON report: schemaVersion: 3, ok: true, project complete: true. This is a static-analysis reproduction; no runtime jank is inferred from the warning.

Create a directory with this package.json, add the file below, and run:

bash
npx --yes [email protected] . --scope full --json --blocking none --yes --no-score
json
{"name":"react-doctor-rule-repros","private":true,"version":"1.0.0","dependencies":{"react":"19.2.7","react-native":"0.86.2","@shopify/flash-list":"2.3.2","@tanstack/react-query":"5.101.0","zustand":"5.0.14"}}

NativePulse.tsx:

typescript
import { useEffect, useState } from 'react';
import { Animated } from 'react-native';

export function NativePulse() {
  const [opacity] = useState(() => new Animated.Value(1));
  useEffect(() => {
    const animation = Animated.loop(
      Animated.timing(opacity, {
        toValue: 0.7,
        duration: 2000,
        useNativeDriver: true,
        isInteraction: false,
      }),
    );
    animation.start();
    return () => animation.stop();
  }, [opacity]);
  return <Animated.View style={{ opacity }} />;
}

Actual

“Your users see stutter when Animated from react-native runs on the JS thread.”

The suggested fix is to switch to Reanimated. The example already delegates animation frames to the native driver, so the diagnostic does not establish the claimed JS-frame work or a reason to migrate.

Expected

Avoid classifying a proven native-driver timing animation as JS-driven. If this remains an import-level heuristic, word the diagnostic as a conditional investigation rather than a runtime defect. A regression test should distinguish this example from useNativeDriver: false; the presence of one native-driver call should not exempt unrelated JS-driven animations in the same file.

Notes

The current rule inspects Animated / LayoutAnimation imports without inspecting animation configuration. These APIs also need separate migration guidance. React Native Animated: using the native driver.