How I reduced app load time by 30% in React Native
When I joined Ehya Education Service, the Classmate app had a noticeable load delay — users on mid-range Android devices waited over 3 seconds before seeing the home screen. Over a few months, we brought that down by 30%. Here's exactly what made the difference.
1. Profiling first, optimizing second
The most common mistake is optimizing blind. I started with the React Native Performance Monitor (shake device → Show Perf Monitor) to establish baselines, then used Flipper with the Hermes Debugger to trace JS thread bottlenecks.
Key finding: 60% of our startup delay was a synchronous data fetch inside useEffect on the root screen — blocking render with no skeleton UI.
2. Lazy loading heavy screens
React Native's default bundler loads all your routes eagerly. Using React.lazy with Suspense wrapped around non-critical screens (Settings, Profile, deep course pages) cut our initial JS bundle parse time significantly.
const Settings = React.lazy(() => import('./screens/Settings'))
// In your navigator:
<Suspense fallback={<LoadingSkeleton />}>
<Settings />
</Suspense>
3. Moving data fetching out of render
We moved our initial API call from useEffect (which runs after first render) to React Query's prefetchQuery at the navigation level — so data is in cache before the screen mounts.
// In the tab navigator's onPress
await queryClient.prefetchQuery({
queryKey: ['home-feed'],
queryFn: fetchHomeFeed,
})
4. Image optimization
Unoptimized images were the silent killer. We switched to expo-image (which uses Glide on Android, SDWebImage on iOS) and added contentFit="cover" with explicit width/height props everywhere — eliminating layout thrash.
Results
| Metric | Before | After | |--------|--------|-------| | Time to interactive | 3.2s | 2.1s | | JS bundle size | 4.1MB | 2.8MB | | ANR rate (Android) | 1.4% | 0.3% |
The 30% figure came from comparing cold-start TTI across 200 real-device sessions in our staging environment.
Performance work is never done — next up is investigating Hermes bytecode precompilation and investigating whether migrating to the New Architecture gives us a meaningful boost on the JS thread.