React Native performance problems look alike from the outside - scrolling stutters, taps feel delayed, screens take a moment to appear - and have distinct causes with distinct fixes. Guessing wastes time, because the most common intuition, that the framework is slow, is almost never the explanation.
01Identify which thread is blocked
Work happens on the JavaScript thread and the UI thread, and which one is saturated tells you what class of problem you have.
If the JS thread is blocked, animations driven by JavaScript stutter but native gestures still respond. If the UI thread is blocked, everything freezes including native scroll. That distinction narrows the search immediately.
JS thread saturation is usually expensive work in render, oversized state updates, or synchronous processing of a large payload. UI thread saturation is usually image decoding, shadows, or too many views.
02The three causes worth checking first
In practice these account for the overwhelming majority of complaints.
- Unvirtualised or badly configured lists. Rendering a long list without recycling, or with a changing key, rebuilds far more than necessary. Stable keys and a properly sized window fix most scroll jank.
- Re-renders from context or state scoped too widely. A context holding frequently changing values re-renders every consumer; splitting it by update frequency is often a one-line fix with a large effect.
- Animations on the JS thread. Anything driven by state updates per frame will stutter under load; the native driver exists precisely so animation survives a busy JS thread.
03Images are the quiet cost
Image handling causes more real-world jank than component structure. Decoding a large image is expensive and happens on the UI thread; a list of full-resolution images will stutter regardless of how well the list is written.
Serve images sized for their display size rather than resizing on device. A 4000-pixel image rendered into a 100-point thumbnail costs full decode for no visual benefit, and in a list it costs it repeatedly.
Cache decoded images, not just downloaded bytes. Re-decoding on every scroll pass is a common and invisible cost.
04When it really is architecture
If you have fixed lists, re-renders and images and the app is still slow, the remaining causes are usually structural: too much state held too high, a data layer that refetches on every focus, or heavy computation that belongs off the main thread.
At that point the fix is not an optimisation but a change in where work happens. Moving parsing and transformation off the JS thread, or memoising derived data properly, resolves what component-level tuning cannot.
Topics
Aarav Patel
Principal Engineer · SyncTrix
Writes about the engineering decisions behind production systems - architecture, delivery and the trade-offs that only show up at scale.
Building something like this?
SyncTrix engineers AI, SaaS, platform and cloud systems for enterprises and high-growth teams. Tell us what you're shipping and we'll scope it with you.
Talk to an engineer