Performance Optimization Mobile — Mobile

Performance Optimization di React Native Mobile device punya resource terbatas — CPU, RAM, battery. Optimasi performa bukan nice-to-have, tapi keharusan untuk u

Performance Optimization di React Native

Mobile device punya resource terbatas — CPU, RAM, battery. Optimasi performa bukan nice-to-have, tapi keharusan untuk user experience yang baik.

Hermes Engine

// Hermes: JS engine optimized untuk React Native
// Default di Expo SDK 50+ dan React Native 0.70+

// Keuntungan Hermes:
// - Startup time 2x lebih cepat
// - Memory usage 30% lebih rendah
// - Bytecode precompilation (AOT)

// Cek apakah Hermes aktif:
const isHermes = () => !!global.HermesInternal;
console.log('Hermes:', isHermes()); // true

FlatList Optimization

import { FlatList } from 'react-native';
import { memo, useCallback } from 'react';

// 1. Memoize render item
const MemoizedItem = memo(({ item }) => (
  <View style={styles.item}>
    <Text>{item.title}</Text>
  </View>
));

function OptimizedList({ data }) {
  // 2. Stable callbacks
  const renderItem = useCallback(
    ({ item }) => <MemoizedItem item={item} />,
    []
  );
  const keyExtractor = useCallback((item) => item.id.toString(), []);

  return (
    <FlatList
      data={data}
      renderItem={renderItem}
      keyExtractor={keyExtractor}
      // 3. Tuning props
      initialNumToRender={10}
      maxToRenderPerBatch={5}
      windowSize={5}
      removeClippedSubviews={true}
      // 4. Estimated item size (skip layout calculation)
      getItemLayout={(data, index) => ({
        length: ITEM_HEIGHT,
        offset: ITEM_HEIGHT * index,
        index,
      })}
    />
  );
}

FlashList — FlatList Replacement

import { FlashList } from '@shopify/flash-list';

// Drop-in replacement, 5x lebih cepat dari FlatList
<FlashList
  data={data}
  renderItem={({ item }) => <ItemComponent item={item} />}
  estimatedItemSize={80}
/>

Image Optimization

// expo-image: pengganti Image bawaan, jauh lebih cepat
import { Image } from 'expo-image';

<Image
  source={{ uri: imageUrl }}
  style={{ width: 200, height: 200 }}
  contentFit="cover"
  placeholder={blurhash}    // Placeholder blur saat loading
  transition={200}           // Fade-in animation
  cachePolicy="memory-disk"  // Aggressive caching
/>

Avoid Re-renders

// BURUK: inline object/function = re-render setiap render cycle
<View style={{ padding: 16 }}> {/* Buat object baru setiap render */}
  <Pressable onPress={() => doSomething()}> {/* Function baru */}
    <Text>Press</Text>
  </Pressable>
</View>

// BAIK: stable reference
const styles = StyleSheet.create({ container: { padding: 16 } });
const handlePress = useCallback(() => doSomething(), []);

<View style={styles.container}>
  <Pressable onPress={handlePress}>
    <Text>Press</Text>
  </Pressable>
</View>

Profiling Tools

Yang akan kamu pelajari