React Native

React Native Performance Optimization Techniques

Performance is critical for mobile applications. Users expect smooth, responsive experiences, and poor performance can lead to app abandonment. This article covers proven techniques for optimizing React Native applications.

List Rendering Optimization

Lists are common in mobile apps and can be performance bottlenecks:

typescript
// ✅ Optimized FlatList
import { FlatList } from 'react-native';

function OptimizedList({ data }: { data: Item[] }) {
  const renderItem = useCallback(({ item }: { item: Item }) => {
    return <ListItem item={item} />;
  }, []);

  const keyExtractor = useCallback((item: Item) => item.id, []);

  const getItemLayout = useCallback(
    (_: any, index: number) => ({
      length: ITEM_HEIGHT,
      offset: ITEM_HEIGHT * index,
      index,
    }),
    []
  );

  return (
    <FlatList
      data={data}
      renderItem={renderItem}
      keyExtractor={keyExtractor}
      getItemLayout={getItemLayout}
      initialNumToRender={10}
      maxToRenderPerBatch={5}
      windowSize={10}
      removeClippedSubviews={true}
    />
  );
}

// ❌ Bad: Using ScrollView for lists
function BadList({ data }: { data: Item[] }) {
  return (
    <ScrollView>
      {data.map(item => <ListItem key={item.id} item={item} />)}
    </ScrollView>
  );
}

Image Optimization

Images are often the largest assets in mobile apps:

typescript
// ✅ Using react-native-fast-image
import FastImage from 'react-native-fast-image';

function OptimizedImage({ uri }: { uri: string }) {
  return (
    <FastImage
      source={{
        uri,
        priority: FastImage.priority.normal,
        cache: FastImage.cacheControl.immutable,
      }}
      resizeMode={FastImage.resizeMode.cover}
      style={{ width: 200, height: 200 }}
    />
  );
}

// ✅ Image caching strategy
const imageCache = {
  get: (uri: string) => {
    // Check memory cache
    // Check disk cache
    // Return cached image or null
  },
  set: (uri: string, image: Image) => {
    // Store in memory cache
    // Store in disk cache
  },
};

Component Optimization

typescript
// ✅ Memoizing expensive components
const ExpensiveListItem = React.memo(({ item }: { item: Item }) => {
  return (
    <View>
      <Text>{item.title}</Text>
      <ComplexVisualization data={item.data} />
    </View>
  );
}, (prevProps, nextProps) => {
  // Custom comparison
  return prevProps.item.id === nextProps.item.id;
});

// ✅ Using useMemo for expensive calculations
function ProductList({ products }: { products: Product[] }) {
  const sortedProducts = useMemo(() => {
    return products.sort((a, b) => a.price - b.price);
  }, [products]);

  return (
    <FlatList
      data={sortedProducts}
      renderItem={({ item }) => <ProductCard product={item} />}
    />
  );
}

Animation Performance

Smooth animations are crucial for user experience:

typescript
// ✅ Using Reanimated for smooth animations
import Animated, { useSharedValue, withSpring } from 'react-native-reanimated';

function AnimatedButton() {
  const scale = useSharedValue(1);

  const handlePress = () => {
    scale.value = withSpring(0.95, {
      damping: 15,
      stiffness: 150,
    });
    setTimeout(() => {
      scale.value = withSpring(1);
    }, 100);
  };

  return (
    <Animated.View style={{ transform: [{ scale }] }}>
      <Button onPress={handlePress} />
    </Animated.View>
  );
}

// ✅ Using native driver
const animatedValue = new Animated.Value(0);

Animated.timing(animatedValue, {
  toValue: 1,
  duration: 300,
  useNativeDriver: true, // ✅ Use native driver
}).start();

Memory Management

Proper memory management prevents crashes:

typescript
// ✅ Cleaning up subscriptions
function UserProfile({ userId }: { userId: string }) {
  useEffect(() => {
    const subscription = userService.subscribe(userId, (user) => {
      setUser(user);
    });

    // Cleanup
    return () => {
      subscription.unsubscribe();
    };
  }, [userId]);

  return <UserDetails user={user} />;
}

// ✅ Limiting image cache
import { ImageCache } from 'react-native-fast-image';

ImageCache.get().clear(); // Clear cache when needed
ImageCache.get().limit(50); // Limit cache size

Conclusion

React Native performance optimization is an ongoing process. By following these techniques and regularly profiling your application, you can create smooth, responsive mobile experiences that users love. Remember to measure before and after optimizations to ensure they're effective.