FlatList 튜닝 — 대규모 리스트 성능 극대화
1만 개의 아이템을 부드럽게 스크롤하려면 FlatList의 내부 동작을 이해하고 적절히 튜닝해야 합니다.
FlatList 성능 속성
<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 최적화
// 나쁜 예: 인라인 함수 → 매번 새 참조 생성
<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배 빠릅니다.
npm install @shopify/flash-list
import { FlashList } from '@shopify/flash-list';
function FastList() {
return (
<FlashList
data={data}
renderItem={({ item }) => <ListItem item={item} />}
estimatedItemSize={80} // 대략적인 아이템 높이 (필수)
// FlatList와 API가 거의 동일
/>
);
}
FlatList vs FlashList
| 항목 | FlatList | FlashList |
|---|---|---|
| 방식 | 뷰 생성/제거 | 셀 재활용 |
| 빈 화면(blank area) | 자주 발생 | 거의 없음 |
| 스크롤 성능 | 최적화 필요 | 기본적으로 빠름 |
| API 호환성 | - | FlatList와 거의 동일 |
| 필수 설정 | keyExtractor | estimatedItemSize |
동적 높이 아이템 최적화
// 아이템 높이가 다를 때
<FlatList
data={data}
renderItem={renderItem}
// getItemLayout을 설정할 수 없으므로 다른 방법 사용
// 초기 스크롤 위치를 위한 대략적 계산
initialScrollIndex={0}
// onViewableItemsChanged로 가시 아이템 추적
onViewableItemsChanged={({ viewableItems }) => {
// 현재 보이는 아이템 기반으로 로직 처리
}}
viewabilityConfig={{
viewAreaCoveragePercentThreshold: 50,
}}
/>
정리
getItemLayout은 고정 높이 아이템에서 ** 가장 큰 성능 향상 **을 제공합니다renderItem에 ** 인라인 함수를 피하고**React.memo와useCallback을 사용하세요windowSize를 줄이면 메모리를 절약하지만, 너무 줄이면 빈 공간이 보입니다- FlashList 는 셀 재활용으로 FlatList보다 5~10배 빠릅니다
- 성능 문제가 있으면 FlatList에서 FlashList로 교체 하는 것을 먼저 고려하세요
댓글 로딩 중...