home/field notes/React Native
React NativePerformance

React Native gestures that actually feel native

Reanimated + Gesture Handler on the UI thread is the difference between a prototype and a product.

KB Kambiz BaghieJan 202610 min

The JS thread is not your friend

Drive an animation from JavaScript and every dropped frame in your business logic shows up as stutter in the user’s thumb. The fix is to run gesture tracking and animation entirely on the UI thread with Reanimated worklets.

A swipeable sheet, frame-perfect

  • Gesture.Pan() writes directly to a shared value — no bridge round-trip.
  • Spring physics with withSpring for the settle, so it decelerates like a real object.
  • Snap points computed on the UI thread so the release always lands cleanly.
const y = useSharedValue(0);
const pan = Gesture.Pan()
  .onChange((e) => { y.value += e.changeY; })
  .onEnd((e) => { y.value = withSpring(snap(y.value, e.velocityY)); });

Mid-range Android is the real test

A flagship hides a lot of sins. Profiling the sheet on a mid-range Android — where the JS thread is genuinely busy — is what proves the gesture is truly off-thread. If it stays smooth there, it’s smooth everywhere.

Working draft. An outline of the real article — the full write-up is on the way. The notes below are genuine takeaways from shipping this in production.