Skip to content
CodeAndBuild LogoCodeAndBuild

React

How to Optimize React Native Apps for Better Performance

A comprehensive guide to fixing performance bottlenecks in React Native apps, improving frame rates, and leveraging the Hermes engine.

CodeAndBuild Team3 min read
  • React Native
  • React
  • Performance
  • Mobile
On this page
  1. 1. Optimize Component Rendering
  2. 2. Leverage FlatList and FlashList efficiently
  3. 3. Image Optimization Strategies
  4. 4. Enable Hermes Engine
  5. 5. Move Animations to the Native Thread
  6. Conclusion

Discover practical strategies and tips to boost the speed, frame rates, and overall performance of your React Native applications. Learn how to manage render cycles, optimize images, and reduce JavaScript thread bottlenecks effectively.

Building mobile applications using React Native offers cross-platform advantages, allowing developers to target both iOS and Android with a single codebase. However, as applications grow in complexity, developers frequently encounter performance issues such as UI lag, dropped frames, slow startup times, and heavy memory usage.

Optimizing a React Native application requires a solid understanding of how JavaScript code interacts with native platform components. In this guide, we will explore key strategies to significantly improve your React Native app's performance.

1. Optimize Component Rendering

Unnecessary re-renders are one of the primary culprits behind sluggish UI performance in React Native apps. Every time a component re-renders unnecessarily, it sends redundant commands across the bridge, consuming valuable JavaScript execution time.

Use React.memo and useCallback

Wrap functional components with React.memo to prevent re-rendering when props haven't changed:

example.jsxjsx
import React from 'react';
import { Text, View } from 'react-native';

const ListItem = React.memo(({ item }) => {
  return (
    <View className="p-4 border-b border-gray-200">
      <Text className="text-lg font-semibold">{item.title}</Text>
    </View>
  );
});

export default ListItem;

Additionally, utilize useCallback to memoize event handler functions so that reference equality remains intact between renders.

2. Leverage FlatList and FlashList efficiently

Rendering large lists of data without virtualizing can quickly freeze your app or crash it due to memory exhaustion.

Never use ScrollView for long lists: Always use FlatList or Shopify’s FlashList for list rendering.

Set key extractor: Ensure every item has a unique string key.

Use getItemLayout: If your list item heights are fixed, providing getItemLayout skips the dynamic layout measurement step, improving scroll smoothness drastically.

3. Image Optimization Strategies

Unoptimized high-resolution images eat up device memory and cause UI stuttering during list scrolling.

Resize Images Server-Side: Serve images in the exact dimension required by the mobile viewport rather than sending 4K images down to a small container.

Use WebP Format: WebP offers high quality at significantly smaller file sizes compared to PNG or JPEG.

Enable Caching: Utilize libraries like react-native-fast-image or Expo's built-in Image component with memory and disk caching turned on.

4. Enable Hermes Engine

Hermes is an open-source JavaScript engine optimized specifically for running React Native on Android and iOS. Enabling Hermes results in:

Faster Time to Interactive (TTI): Apps load and become responsive much faster upon initial open.

Reduced APK/IPA Size: Decreased initial download footprint.

Lower Memory Footprint: Efficient garbage collection tailored for mobile environments.

Ensure Hermes is enabled in your android/app/build.gradle and ios/Podfile setup.

5. Move Animations to the Native Thread

Executing complex animations on the main JavaScript thread causes frames to drop whenever background tasks or API calls execute.

Always use React Native Reanimated or the built-in Animated API with useNativeDriver: true:

example.jsjs
Animated.timing(fadeAnim, {
  toValue: 1,
  duration: 500,
  useNativeDriver: true, // Offloads execution to the native thread
}).start();

Conclusion

Optimizing a React Native application is an ongoing process of profiling, identifying bottlenecks, and applying targeted improvements. By controlling re-renders, using optimized lists, serving compressed images, enabling the Hermes engine, and offloading animations to the native thread, you can deliver a smooth, responsive, and native-feeling user experience.

Found this useful? Send it to someone building the same thing.

Sharing is the main way new readers find CodeAndBuild. One click posts this guide with its cover image.

ReactUICSS

Use One Glass Shell for Login and Signup

One glass stage, two forms. How to share the shell between sign-in and create-account without cloning the CSS.

8 min read