FlatList는 요소 가상화를 통해 고성능 리스트를 표시하는 React Native의 주요 컴포넌트입니다. ScrollView와 달리 FlatList는 화면에 보이는 요소만 렌더링하여 메모리와 CPU를 절약합니다. 이 컴포넌트는 수평 및 수직 스크롤, 풀-투-리프레시, 무한 로딩을 지원합니다. 리스트 아키텍처에 대한 자세한 내용은 Meta 문서에서 확인하세요.
핵심 포인트
FlatList는 대용량 데이터 세트를 고성능으로 렌더링하는 가상화 리스트를 구현한 React Native 컴포넌트입니다. 이 컴포넌트는 VirtualizedList 위에 구축되었으며, 모든 복잡성의 플랫 리스트를 생성하기 위한 선언적 API를 제공합니다.
FlatList는 React Native 0.43에서 구형 ListView를 대체하기 위해 도입되었습니다. Meta(2026년)에 따르면 FlatList는 리스트를 사용하는 React Native 애플리케이션의 85%에서 사용됩니다. 이 컴포넌트는 연락처, 뉴스 피드, 제품 카탈로그, 채팅 등 모든 일반적인 시나리오를 지원합니다.
FlatList 이전에는 개발자들이 수동으로 셀 재사용을 구성해야 하는 ListView를 사용했습니다. FlatList는 Android의 RecyclerView(2014년)와 iOS의 UICollectionView(2012년)와 유사한 윈도우 렌더링을 구현하여 이 프로세스를 자동화했습니다. 현대 프로젝트에서 FlatList는 모든 리스트의 사실상 표준입니다.
FlatList 가상화는 컴포넌트가 화면의 보이는 영역에 속하는 요소와 각 측면의 작은 버퍼만 렌더링하는 메커니즘입니다. 나머지 요소는 DOM에 생성되지 않아 메모리를 절약하고 렌더링을 가속화합니다.
스크롤할 때 FlatList는 이미 생성된 View 셀을 재사용하여 데이터를 교체합니다. 이렇게 하면 10,000개 요소의 리스트에 대해 수천 개의 View가 생성되는 것을 방지합니다. 기본 버퍼 크기는 보이는 영역 위아래로 각각 10개 요소이지만 windowSize를 통해 구성할 수 있습니다.
| 매개변수 | 기본값 | 설명 |
|---|---|---|
| windowSize | 21 | 렌더링할 페이지 수 (1페이지 = 화면 높이) |
| initialNumToRender | 10 | 첫 렌더링 시 요소 수 |
| maxToRenderPerBatch | 10 | 배치당 최대 렌더링 요소 수 |
| removeClippedSubviews | false | 화면 밖의 View를 계층 구조에서 제거 |
이러한 매개변수의 최적 구성은 스크롤 부드러움과 메모리 소비 간의 균형을 유지할 수 있게 해줍니다. 큰 요소가 있는 리스트의 경우 windowSize를 5-7로 줄이는 것이 좋습니다.
FlatList API에는 리스트 표시와 동작을 구성하기 위한 일련의 Props가 포함됩니다. 필수 Props는 data(데이터 배열)와 renderItem(요소 렌더링 함수)입니다. keyExtractor는 각 요소에 고유 키를 제공하여 성능을 향상시킵니다.
import React from 'react';
import { FlatList, View, Text, StyleSheet } from 'react-native';
const App = () => {
const data = Array.from({ length: 100 }, (_, i) => ({
id: i.toString(),
title: `Item #${i + 1}`,
}));
return (
<FlatList
data={data}
renderItem={({ item }) => (
<View style={styles.item}>
<Text>{item.title}</Text>
</View>
)}
keyExtractor={item => item.id}
ItemSeparatorComponent={() => <View style={styles.separator} />}
/>
);
};ItemSeparatorComponent는 요소 사이에 구분선을 추가하고, ListHeaderComponent와 ListFooterComponent는 리스트에 헤더와 푸터를 추가합니다. 이를 통해 추가 래퍼 없이 복잡한 레이아웃을 만들 수 있습니다.
const styles = StyleSheet.create({
item: {
padding: 16,
backgroundColor: '#fff',
borderBottomWidth: 1,
borderBottomColor: '#e0e0e0',
},
separator: {
height: 1,
backgroundColor: '#ccc',
},
});FlatList 최적화는 수백, 수천 개의 요소를 가진 애플리케이션에 매우 중요합니다. 올바르게 구성하지 않으면 스크롤 시 리스트가 느려지고, 과도한 메모리를 소비하며, 저사양 기기에서 충돌이 발생할 수 있습니다.
첫 번째 규칙은 고유하고 안정적인 식별자와 함께 keyExtractor를 사용하는 것입니다. 인덱스를 키로 사용하면 잘못된 셀 재사용과 상태 버그가 발생합니다. 두 번째 규칙은 renderItem을 useCallback으로 감싸고 요소 컴포넌트에 React.memo를 사용하는 것입니다.
모든 요소의 높이가 같으면 getItemLayout을 통해 FlatList가 컴포넌트를 측정하지 않고 스크롤 위치를 계산할 수 있습니다. 이는 특히 특정 인덱스로 스크롤할 때 상당한 성능 향상을 제공합니다.
const ITEM_HEIGHT = 80;
const getItemLayout = (data, index) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index,
});
<FlatList
data={data}
getItemLayout={getItemLayout}
renderItem={renderItem}
/FlatList>데이터에 대한 useMemo는 불필요한 리렌더링을 방지합니다. 데이터가 API에서 오는 경우 한 번 변환하여 캐시하세요. 요소 컴포넌트에 React.memo를 사용하여 변경되지 않은 요소의 렌더링을 방지하세요.
수평 FlatList는 horizontal={true} prop을 추가하여 생성합니다. 리스트의 스크롤 방향이 X축으로 변경되어 제품 캐러셀, 이미지 갤러리, 수평 메뉴에 편리합니다.
수평 모드에서는 네이티브 캐러셀처럼 단계별 스크롤을 위해 snapToInterval과 snapToAlignment를 올바르게 구성하는 것이 중요합니다. 컴포넌트는 자동으로 관성과 손가락 떼기를 처리하여 가장 가까운 요소에서 멈춥니다.
<FlatList
horizontal
data={images}
renderItem={renderItem}
keyExtractor={item => item.id}
showsHorizontalScrollIndicator={false}
snapToInterval={CARD_WIDTH + GAP}
snapToAlignment="start"
decelerationRate="fast"
pagingEnabled
onViewableItemsChanged={onViewableItemsChanged}
/>onViewableItemsChanged는 보이는 요소가 변경될 때 트리거되는 콜백입니다. 분석, 이미지 지연 로딩, 보이는 카드에 대해서만 비디오 활성화에 사용됩니다.
풀-투-리프레시는 FlatList에서 refreshing과 onRefresh props를 통해 구현되며, 로딩 상태와 함께 작동합니다. 리스트를 아래로 당기면 onRefresh가 호출되고 refreshing 플래그가 반복 호출을 차단합니다.
무한 스크롤은 onEndReached를 통해 구성됩니다 — 리스트 끝에 가까워지면 트리거되는 콜백입니다. onEndReachedThreshold는 끝에서 몇 개 요소 전에 이벤트가 발생할지 결정합니다. 일반적으로 커서 기반 페이지네이션이 사용됩니다.
const ListWithPagination = () => {
const [data, setData] = React.useState([]);
const [page, setPage] = React.useState(1);
const [refreshing, setRefreshing] = React.useState(false);
const loadMore = React.useCallback(async () => {
const newData = await fetchPage(page);
setData(prev => [...prev, ...newData]);
setPage(p => p + 1);
}, [page]);
return (
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={item => item.id}
refreshing={refreshing}
onRefresh={loadMore}
onEndReached={loadMore}
onEndReachedThreshold={0.5}
/>
);
};중요: onEndReached는 여러 번 호출될 수 있습니다. 이전 요청이 완료될 때까지 반복 요청을 차단하기 위해 isLoading 플래그를 추가하세요. 로딩을 표시하려면 ListFooterComponent에서 ActivityIndicator를 사용하세요.
자주 묻는 질문
FlatList는 가상화를 사용하여 보이는 요소만 렌더링하므로 대용량 데이터에서 메모리를 절약합니다. ScrollView는 모든 자식 요소를 한 번에 렌더링하며 20-30개 요소의 작은 리스트에만 적합합니다. FlatList는 100개 이상의 요소에 최적입니다.
데이터 배열의 참조가 변경될 때 깜빡임이 발생합니다. extraData를 사용하여 종속성을 전달하거나 renderItem을 React.memo로 감싸세요. 완전한 제어를 위해 useMemo를 사용하여 데이터 참조를 안정화하세요.
FlatList는 제스처 충돌로 인해 ScrollView 내부에 중첩되도록 설계되지 않았습니다. 해결책: nestedScrollEnabled(Android)와 함께 FlatList 사용, 섹션용 SectionList 사용, 또는 ListHeaderComponent를 통해 외부 스크롤을 FlatList로 이동하세요.
인덱스 기반 지연과 함께 renderItem 내에서 Animated API를 사용하세요. 스크롤 시 onViewableItemsChanged를 사용하여 애니메이션을 트리거하세요. react-native-reanimated 및 react-native-lottie 라이브러리는 복잡한 나타남 애니메이션 생성을 간소화합니다.
VirtualizedList는 FlatList와 SectionList가 구축되는 기본 가상화 컴포넌트입니다. FlatList는 플랫 리스트를 위한 단순화된 API를 제공하는 VirtualizedList의 래퍼입니다. VirtualizedList는 더 낮은 수준의 제어를 제공하지만 직접 사용되는 경우는 드뭅니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.