hardReact Native#20

InteractionManager for heavy ops

Prompt

Use InteractionManager.runAfterInteractions to defer a heavy computation (simulated with a loop of 100M iterations) until after navigation transitions complete.

Solution

useEffect(() => {
  const task = InteractionManager.runAfterInteractions(() => {
    let result = 0
    for (let i = 0; i < 100_000_000; i++) result += i
    setReady(true)
  })
  return () => task.cancel()
}, [])
if (!ready) return <Text>Preparing...</Text>
return <Text>Ready</Text>
Mentor's take

The failure mode this solves is structural: a JS-driven navigation transition and your mount-time heavy work compete for the same JS thread, so the transition stutters. InteractionManager.runAfterInteractions sequences instead of competing — defer the expensive work, keep the transition's frame budget intact, run the work immediately after.

Mechanically it's a handle registry, not magic: animations register an interaction handle (createInteractionHandle) and release it when done — the Animated API does this internally. While any handle is open, deferred callbacks queue; when the count hits zero, the queue flushes. That mechanism defines its blind spot, and naming it is the senior move: UI-thread animations — native-driver Animated and Reanimated worklets — never register JS-side handles, so runAfterInteractions can resolve while such a transition is still visibly running. For navigation specifically, React Navigation's transition-end events are the more precise deferral point.

Two production details in the code: task.cancel() in the effect cleanup stops the deferred work if the user backs out before it runs, and the ready placeholder means the screen paints something immediately — deferral plus skeleton, not a blank frame. And honestly: a 100M-iteration loop will still freeze the JS thread when it runs; InteractionManager schedules work, it doesn't parallelize it. Truly heavy compute belongs off-thread.

Red flag: claiming InteractionManager "detects when animations finish." It only sees explicitly registered handles.

Say it: "runAfterInteractions defers JS-thread work until registered interaction handles release — but native-driver and Reanimated animations are invisible to it, so for navigation I prefer transition-end events."