1만 개의 아이템을 부드럽게 스크롤하려면 FlatList의 내부 동작을 이해하고 적절히 튜닝해야 합니다.


FlatList 성능 속성

TSX
<FlatList
  data={largeData}
  renderItem={renderItem}
  keyExtractor={keyExtractor}

  // 1. getItemLayout — 가장 큰 성능 향상
  // 아이템 높이가 고정이면 반드시 설정
  getItemLayout={(_, index) => ({
    length: 80,           // 아이템 높이
    offset: 80 * index,   // 누적 높이
    index,
  })}

  // 2. windowSize — 렌더링 범위 (기본: 21)
  // 값이 작을수록 메모리 절약, 크면 빈 공간 감소
  windowSize={5}

  // 3. maxToRenderPerBatch — 한 번에 렌더링할 아이템 수
  maxToRenderPerBatch={10}

  // 4. initialNumToRender — 초기 렌더링 아이템 수
  initialNumToRender={10}

  // 5. removeClippedSubviews — 화면 밖 뷰 제거 (Android)
  removeClippedSubviews={true}

  // 6. updateCellsBatchingPeriod — 배치 렌더링 간격 (ms)
  updateCellsBatchingPeriod={50}
/>

renderItem 최적화

TSX
// 나쁜 예: 인라인 함수 → 매번 새 참조 생성
<FlatList
  renderItem={({ item }) => <ListItem item={item} onPress={() => handlePress(item.id)} />}
/>

// 좋은 예: 메모이제이션된 컴포넌트 + 안정적인 콜백
const MemoizedItem = React.memo(function ListItem({ item, onPress }: Props) {
  return (
    <Pressable onPress={() => onPress(item.id)}>
      <Text>{item.title}</Text>
    </Pressable>
  );
});

function List() {
  const handlePress = useCallback((id: string) => {
    navigation.navigate('Detail', { id });
  }, []);

  const renderItem = useCallback(({ item }: { item: Item }) => (
    <MemoizedItem item={item} onPress={handlePress} />
  ), [handlePress]);

  return <FlatList data={data} renderItem={renderItem} />;
}

FlashList — FlatList 대안

Shopify가 만든 고성능 리스트 컴포넌트입니다. 셀 재활용(recycling) 방식으로 FlatList보다 5~10배 빠릅니다.

BASH
npm install @shopify/flash-list
TSX
import { FlashList } from '@shopify/flash-list';

function FastList() {
  return (
    <FlashList
      data={data}
      renderItem={({ item }) => <ListItem item={item} />}
      estimatedItemSize={80}  // 대략적인 아이템 높이 (필수)
      // FlatList와 API가 거의 동일
    />
  );
}

FlatList vs FlashList

항목FlatListFlashList
방식뷰 생성/제거셀 재활용
빈 화면(blank area)자주 발생거의 없음
스크롤 성능최적화 필요기본적으로 빠름
API 호환성-FlatList와 거의 동일
필수 설정keyExtractorestimatedItemSize

동적 높이 아이템 최적화

TSX
// 아이템 높이가 다를 때
<FlatList
  data={data}
  renderItem={renderItem}
  // getItemLayout을 설정할 수 없으므로 다른 방법 사용

  // 초기 스크롤 위치를 위한 대략적 계산
  initialScrollIndex={0}

  // onViewableItemsChanged로 가시 아이템 추적
  onViewableItemsChanged={({ viewableItems }) => {
    // 현재 보이는 아이템 기반으로 로직 처리
  }}
  viewabilityConfig={{
    viewAreaCoveragePercentThreshold: 50,
  }}
/>

정리

  • getItemLayout은 고정 높이 아이템에서 ** 가장 큰 성능 향상 **을 제공합니다
  • renderItem에 ** 인라인 함수를 피하고** React.memouseCallback을 사용하세요
  • windowSize를 줄이면 메모리를 절약하지만, 너무 줄이면 빈 공간이 보입니다
  • FlashList 는 셀 재활용으로 FlatList보다 5~10배 빠릅니다
  • 성능 문제가 있으면 FlatList에서 FlashList로 교체 하는 것을 먼저 고려하세요
댓글 로딩 중...