After building React Native apps for years, I’ve come to realise something painful: most performance issues don’t scream. They whisper. Your app might work fine on your device — smooth animations, fast loads — until one day a user with an older Android phone opens it and it feels like it's running underwater. That’s when the complaints start rolling in. Been there? Yeah, me too. So here’s a list of performance tips I wish someone had tattooed on my screen earlier in my React Native journey. These are real-world lessons, not theoretical fluff — and they’ve saved me more than once. 1. Avoid Anonymous Functions in JSX It’s tempting to inline logic, especially when the function is short. But anonymous functions in your render tree trigger unnecessary re-renders. // ❌ This creates a new function every render doSomething()} /> // ✅ Better: use useCallback const handlePress = useCallback(() => { doSomething(); }, []); Even small optimizations like this can make a noticeable difference when you're rendering long lists or complex UI. 2. Use FlatList Instead of ScrollView for Lists This one’s simple but often overlooked. When rendering large datasets, always use FlatList — it’s virtualized, meaning it only renders what’s visible on the screen. Key props to fine-tune performance: Avoid ScrollView for dynamic or long content. It renders everything, which kills performance. 3. Don’t Overuse useEffect I see a lot of devs use useEffect as a default hook for everything data fetching, logging, side effects. It’s powerful, but overuse can lead to memory leaks, double-fetches, and unnecessary re-renders. Be intentional. Sometimes, derived state or simple conditional logic is all you need. And don’t forget to clean up your effects. useEffect(() => { const subscription = doSomething(); return () => { subscription?.unsubscribe(); }; }, []); 4. Memoization is Your Friend React renders are cheap — until they’re not. Use: React.memo() for functional components useMemo() for expensive calculations useCallback() for functions passed as props But don’t go overboard — memoization has its own cost. Use it strategically. 5. Optimize Images Unoptimized images are one of the biggest silent killers of performance, especially on slower networks. Here’s what helped: Use react-native-fast-image — better caching and decoding Compress images before shipping Lazy load images when possible (e.g., with onEndReached in FlatList) 6. Turn On Hermes (Seriously) Hermes is a JavaScript engine optimized for React Native on Android. If your app is sluggish on Android, enabling Hermes can dramatically reduce load times and memory usage. How to enable it: android { ... defaultConfig { ... jscFlavor: 'org.webkit:android-jsc-intl:+' } buildTypes { release { ... shrinkResources true minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } Enable in android/app/build.gradle and rebuild. You'll feel the difference, especially on older Android devices. 7. Trim the Fat: Dependencies & JS Bloat It’s easy to add another library to solve a problem — but every dependency adds to your bundle size and startup time. ✅ Tips: Audit dependencies regularly Remove unused polyfills Avoid dev tools in production (e.g., redux-logger, Flipper, etc.) Use why-did-you-render during dev to find unnecessary renders and bloat. 8. Profile Your App Like a Detective Don't guess. Measure. Tools I recommend: Flipper – React DevTools + performance monitoring Android Profiler – CPU & memory usage Xcode Instruments – for iOS diagnostics React DevTools – check component re-renders Spend time here. You’ll be surprised where bottlenecks hide. 9. Use Native Driver in Animations React Native’s JS thread is fragile — animations that rely on it can easily get choppy. When using Animated, always enable the native driver: Animated.timing(animatedValue, { toValue: 1, duration: 300, useNativeDriver: true, }).start(); Or go further and explore Reanimated 3, which is designed to run animations entirely on the native thread. 10. Prefer Lightweight Libraries Every dependency has a cost. Here’s what I use in place of heavier tools: Zustand or Jotai instead of Redux (for smaller apps) react-native-mmkv instead of AsyncStorage React Query or SWR instead of hand-rolled fetch logic These small shifts have made my apps leaner and faster. ✅ Final Thoughts Performance isn’t about perfection — it’s about awareness. When you know what to look for, and how React Native works under the hood, it becomes easier to write faster, smoother apps from the start. The good news? You don’t need to be a wizard. You just need the right habits. Hope these tips help you avoid the mistakes I made. Got a perfor

Apr 17, 2025 - 08:18
 0

After building React Native apps for years, I’ve come to realise something painful: most performance issues don’t scream. They whisper.

Your app might work fine on your device — smooth animations, fast loads — until one day a user with an older Android phone opens it and it feels like it's running underwater. That’s when the complaints start rolling in. Been there? Yeah, me too.

So here’s a list of performance tips I wish someone had tattooed on my screen earlier in my React Native journey. These are real-world lessons, not theoretical fluff — and they’ve saved me more than once.

1. Avoid Anonymous Functions in JSX

It’s tempting to inline logic, especially when the function is
short. But anonymous functions in your render tree trigger
unnecessary re-renders.

// ❌ This creates a new function every render

Even small optimizations like this can make a noticeable difference when you're rendering long lists or complex UI.

2. Use FlatList Instead of ScrollView for Lists

This one’s simple but often overlooked. When rendering large
datasets, always use FlatList — it’s virtualized, meaning it only
renders what’s visible on the screen.

Key props to fine-tune performance:

 

Avoid ScrollView for dynamic or long content. It renders everything,
which kills performance.

3. Don’t Overuse useEffect

I see a lot of devs use useEffect as a default hook for everything data fetching, logging, side effects. It’s powerful, but overuse can lead to memory leaks, double-fetches, and unnecessary re-renders.

Be intentional. Sometimes, derived state or simple conditional logic is all you need. And don’t forget to clean up your effects.

useEffect(() => {
  const subscription = doSomething();
  return () => {
    subscription?.unsubscribe();
  };
}, []);

4. Memoization is Your Friend

React renders are cheap — until they’re not.

Use:
React.memo() for functional components

useMemo() for expensive calculations

useCallback() for functions passed as props

But don’t go overboard — memoization has its own cost. Use it strategically.

5. Optimize Images

Unoptimized images are one of the biggest silent killers of performance, especially on slower networks.

Here’s what helped:

Use react-native-fast-image — better caching and decoding

Compress images before shipping

Lazy load images when possible (e.g., with onEndReached in FlatList)

6. Turn On Hermes (Seriously)

Hermes is a JavaScript engine optimized for React Native on Android. If your app is sluggish on Android, enabling Hermes can dramatically reduce load times and memory usage.

How to enable it:

android {
  ...
  defaultConfig {
    ...
    jscFlavor: 'org.webkit:android-jsc-intl:+'
  }
  buildTypes {
    release {
      ...
      shrinkResources true
      minifyEnabled true
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
  }
}

Enable in android/app/build.gradle and rebuild. You'll feel the difference, especially on older Android devices.

7. Trim the Fat: Dependencies & JS Bloat

It’s easy to add another library to solve a problem — but every dependency adds to your bundle size and startup time.

✅ Tips:

Audit dependencies regularly

Remove unused polyfills

Avoid dev tools in production (e.g., redux-logger, Flipper, etc.)

Use why-did-you-render during dev to find unnecessary renders and bloat.

8. Profile Your App Like a Detective

Don't guess. Measure.

Tools I recommend:

Flipper – React DevTools + performance monitoring

Android Profiler – CPU & memory usage

Xcode Instruments – for iOS diagnostics

React DevTools – check component re-renders

Spend time here. You’ll be surprised where bottlenecks hide.

9. Use Native Driver in Animations

React Native’s JS thread is fragile — animations that rely on it can easily get choppy. When using Animated, always enable the native driver:

Animated.timing(animatedValue, {
  toValue: 1,
  duration: 300,
  useNativeDriver: true,
}).start();

Or go further and explore Reanimated 3, which is designed to run animations entirely on the native thread.

10. Prefer Lightweight Libraries

Every dependency has a cost.

Here’s what I use in place of heavier tools:

Zustand or Jotai instead of Redux (for smaller apps)

react-native-mmkv instead of AsyncStorage

React Query or SWR instead of hand-rolled fetch logic

These small shifts have made my apps leaner and faster.

✅ Final Thoughts
Performance isn’t about perfection — it’s about awareness.

When you know what to look for, and how React Native works under the hood, it becomes easier to write faster, smoother apps from the start. The good news? You don’t need to be a wizard. You just need the right habits.

Hope these tips help you avoid the mistakes I made. Got a performance win or horror story? Drop it in the comments — I’d love to hear it!