Back to Insights
Mobile

Mobile App Performance Optimization Tips

Sarah Ahmed Dec 28, 2025 9 min read

Speed Matters in Mobile Apps

Mobile users expect fast, responsive apps. Here’s how to optimize performance in React Native and Flutter for the best user experience.

Why Performance Matters

  • User retention - Slow apps get uninstalled
  • App store ratings - Performance affects reviews
  • Battery life - Efficient apps drain less battery
  • User satisfaction - Speed equals happy users
  • Conversion rates - Fast apps convert better

Image Optimization

Images are often the biggest performance bottleneck.

Best Practices:

  • Use appropriate formats

    • WebP for web and Android
    • HEIF for iOS
    • SVG for icons and logos
  • Implement lazy loading

    • Load images only when visible
    • Use placeholder images
    • Progressive image loading
  • Compress images

    • Use tools like TinyPNG
    • Set appropriate quality levels
    • Generate multiple sizes
  • Cache images

    • Use react-native-fast-image
    • Implement disk caching
    • Set cache policies
// React Native example
import FastImage from "react-native-fast-image";

<FastImage
  source={{
    uri: "https://example.com/image.jpg",
    priority: FastImage.priority.normal,
  }}
  resizeMode={FastImage.resizeMode.cover}
/>;

Code Splitting and Lazy Loading

Load code only when needed.

React Native:

import React, { lazy, Suspense } from "react";

const HeavyComponent = lazy(() => import("./HeavyComponent"));

function App() {
  return (
    <Suspense fallback={<Loading />}>
      <HeavyComponent />
    </Suspense>
  );
}

Flutter:

// Use deferred loading
import 'package:myapp/heavy_screen.dart' deferred as heavy;

void loadHeavyScreen() {
  heavy.loadLibrary().then((_) {
    Navigator.push(/* navigate to screen */);
  });
}

Minimize Re-renders

Unnecessary re-renders kill performance.

React Native:

// Use React.memo
const ExpensiveComponent = React.memo(({ data }) => {
  return <View>{/* render data */}</View>;
});

// Use useMemo
const expensiveValue = useMemo(() => {
  return computeExpensiveValue(data);
}, [data]);

// Use useCallback
const handlePress = useCallback(() => {
  doSomething(id);
}, [id]);

Flutter:

// Use const constructors
const MyWidget(
  key: Key('my-key'),
  child: Text('Hello'),
)

// Use keys appropriately
ListView.builder(
  itemBuilder: (context, index) {
    return MyItem(
      key: ValueKey(items[index].id),
      item: items[index],
    );
  },
)

Optimize List Performance

Long lists need special attention.

React Native - Use FlatList:

<FlatList
  data={items}
  renderItem={({ item }) => <ItemComponent item={item} />}
  keyExtractor={(item) => item.id}
  removeClippedSubviews={true}
  maxToRenderPerBatch={10}
  updateCellsBatchingPeriod={50}
  initialNumToRender={10}
  windowSize={10}
  getItemLayout={(data, index) => ({
    length: ITEM_HEIGHT,
    offset: ITEM_HEIGHT * index,
    index,
  })}
/>

Flutter - Use ListView.builder:

ListView.builder(
  itemCount: items.length,
  itemBuilder: (context, index) {
    return ItemWidget(item: items[index]);
  },
  cacheExtent: 100, // Preload items
)

Reduce Bridge Communication (React Native)

Minimize calls across the JavaScript-native bridge.

Batch Updates:

// Bad: Multiple setState calls
setState({ count: count + 1 });
setState({ name: "John" });
setState({ age: 30 });

// Good: Single setState call
setState({
  count: count + 1,
  name: "John",
  age: 30,
});

Use Native Modules:

For performance-critical operations, write native modules:

// Android native module
@ReactMethod
public void processData(ReadableArray data, Promise promise) {
  // Process data natively for better performance
}

Profile Your App

Use profiling tools to identify bottlenecks.

React Native:

  • React DevTools Profiler - Identify slow components
  • Flipper - Network, layout, and performance debugging
  • Systrace - Android performance profiling
  • Instruments - iOS performance profiling

Flutter:

  • Flutter DevTools - Comprehensive debugging
  • Performance Overlay - FPS and render times
  • Timeline View - Frame analysis
  • Memory View - Memory usage tracking

Optimize Network Requests

Network operations can block the UI.

Best Practices:

  • Cache API responses

    import AsyncStorage from "@react-native-async-storage/async-storage";
    
    const cacheResponse = async (key, data) => {
      await AsyncStorage.setItem(key, JSON.stringify(data));
    };
  • Batch requests

    • Combine multiple API calls
    • Use GraphQL for precise data fetching
    • Implement request queuing
  • Implement offline-first

    • Cache data locally
    • Sync when online
    • Show cached data immediately
  • Use compression

    • Enable gzip/brotli
    • Minimize payload size
    • Remove unnecessary data

Memory Management

Prevent memory leaks and crashes.

React Native:

// Clean up subscriptions
useEffect(() => {
  const subscription = eventEmitter.addListener("event", handler);

  return () => {
    subscription.remove();
  };
}, []);

// Cancel pending requests
useEffect(() => {
  const controller = new AbortController();

  fetch(url, { signal: controller.signal });

  return () => {
    controller.abort();
  };
}, []);

Flutter:

@override
void dispose() {
  // Dispose controllers
  _controller.dispose();
  // Cancel subscriptions
  _subscription.cancel();
  super.dispose();
}

Animation Optimization

Smooth animations enhance user experience.

Use Native Driver (React Native):

Animated.timing(animatedValue, {
  toValue: 1,
  duration: 300,
  useNativeDriver: true, // Run on native thread
}).start();

Use Transform Instead of Layout Changes:

// Good: Use transform
transform: [{ translateX: animatedValue }];

// Bad: Change layout properties
left: animatedValue; // Triggers layout recalculation

Flutter Animations:

// Use AnimatedBuilder for complex animations
AnimatedBuilder(
  animation: _controller,
  builder: (context, child) {
    return Transform.translate(
      offset: Offset(_controller.value * 100, 0),
      child: child,
    );
  },
  child: MyWidget(),
)

Bundle Size Optimization

Smaller apps download and launch faster.

React Native:

  • Remove unused dependencies
  • Use Hermes JavaScript engine
  • Enable Proguard (Android)
  • Implement code splitting

Flutter:

  • Use --split-debug-info
  • Enable obfuscation
  • Remove unused code
  • Optimize assets

Testing Performance

Measure improvements objectively.

Key Metrics:

  • Time to Interactive (TTI) - When app becomes usable
  • Frame rate (FPS) - Should stay at 60 FPS
  • Bundle size - Smaller is better
  • Memory usage - Watch for leaks
  • Battery drain - Efficient apps use less power

Conclusion

Performance optimization is an ongoing process. Profile your app regularly, fix the biggest bottlenecks first, and always test on real devices. Remember: what works in the simulator might perform differently on actual hardware. Keep monitoring, keep optimizing, and your users will thank you with better ratings and engagement.

Share This Insight

Related Insights

View All