FlatList는 목록 아이템을 효율적으로 로드하기 위해 사용되는 컨테이너 컴포넌트입니다. 헤더와 푸터 지원, 다중 컬럼(multiple column) 레이아웃, 세로/가로 스크롤, 지연 로딩(lazy loading) 등 모바일 앱에서 리스트를 구현할 때 필요한 기능을 대부분 갖추고 있습니다.
FlatList의 주요 특징
- 스크롤 시 데이터를 점진적으로 로드하는 scroll loading 지원
- ScrollToIndex를 이용한 스크롤 위치 제어
- 헤더(Header) 및 푸터(Footer) 컴포넌트 지원
- 다중 컬럼(Multiple Column) 레이아웃 지원
- iOS와 Android를 동시에 지원하는 크로스 플랫폼
- 화면에 보이는 항목을 감지할 수 있는 viewability 콜백 설정 가능
FlatList의 기본 구조는 다음과 같습니다.
<FlatList
data={DataContainer}
renderItem={yourRenderItem}
keyExtractor={item => item.id} />
FlatList는 내부적으로 VirtualizedList 컴포넌트를 기반으로 구현되어 있습니다. VirtualizedList는 현재 모바일 화면(viewport)에 표시될 수 있는 항목만 렌더링하고, 나머지 데이터는 사용자가 스크롤할 때마다 필요한 만큼만 그려줍니다. 덕분에 대량의 데이터를 다룰 때도 성능 저하 없이 부드러운 스크롤 경험을 제공합니다.
FlatList를 사용하려면 react-native에서 다음과 같이 임포트해야 합니다.
import { FlatList } from "react-native";
FlatList의 주요 Props 정리
| Props | 설명 |
|---|---|
| data | 화면에 표시할 데이터가 담긴 배열입니다. |
| renderItem | renderItem({ item, index, separators }) 형태로 호출됩니다.
separators.highlight(), separators.unhighlight(), separators.updateProps() |
| ListEmptyComponent | 리스트가 비어 있을 때 호출되는 컴포넌트 클래스, 렌더 함수 또는 렌더 요소입니다. 빈 목록 상황에서 안내 메시지 등을 보여주고 싶을 때 유용합니다. |
| ListFooterComponent | 모든 항목의 맨 아래에 렌더링되는 컴포넌트 클래스, 렌더 함수 또는 렌더 요소입니다. |
| ListFooterComponentStyle | 푸터 컴포넌트에 적용할 스타일을 지정합니다. |
| ListHeaderComponent | 모든 항목의 맨 위에 렌더링되는 컴포넌트 클래스, 렌더 함수 또는 렌더 요소입니다. |
| ListHeaderComponentStyle | 헤더 컴포넌트에 적용할 스타일을 지정합니다. |
| horizontal | true로 설정하면 항목들이 가로 방향으로 렌더링됩니다. |
| keyExtractor | 주어진 인덱스에서 고유 키(key)를 추출합니다. 이 키는 캐싱과 항목 재정렬(re-ordering) 추적에 사용됩니다. 시그니처는 (item: object, index: number) => string 입니다. |
예제 1: FlatList 항목을 세로로 표시하기
먼저 FlatList와 함께 사용할 컴포넌트들을 임포트합니다.
import { FlatList, Text, View, StyleSheet } from "react-native";
다음으로 FlatList에 표시할 데이터를 준비합니다. 여기서는 this.state.data에 배열 형태로 저장했습니다.
this.state = {
data: [
{ name: "Javascript Frameworks", isTitle: true },
{ name: "Angular", isTitle: false },
{ name: "ReactJS", isTitle: false },
{ name: "VueJS", isTitle: false },
{ name: "ReactNative", isTitle: false },
{ name: "PHP Frameworks", isTitle: true },
{ name: "Laravel", isTitle: false },
{ name: "CodeIgniter", isTitle: false },
{ name: "CakePHP", isTitle: false },
{ name: "Symfony", isTitle: false }
],
stickyHeaderIndices: []
};
renderItem 함수 구현
renderItem은 전달받은 item을 Text 컴포넌트로 화면에 출력하는 역할을 합니다.
renderItem = ({ item }) => {
return (
<View style={styles.item}>
<Text style={{ fontWeight: (item.isTitle) ? "bold" : "",
color: (item.isTitle) ? "red" : "gray" }}>
{item.name}
</Text>
</View>
);
};
Text 컴포넌트는 View 컴포넌트로 감싸져 있으며, item.isTitle 값이 true인지 false인지에 따라 글자를 굵게(bold) 표시하고 색상도 다르게 적용합니다.
FlatList 구현
data와 renderItem props를 사용한 FlatList 구현 코드는 다음과 같습니다.
<View style={styles.container}>
<FlatList data={this.state.data} renderItem={this.renderItem}
keyExtractor={item => item.name} />
</View>
this.state.data가 data props에 전달되고, this.renderItem 함수가 renderItem props에 할당됩니다.
keyExtractor에는 데이터 배열에서 고유한 값을 가지는 속성을 지정해야 합니다. 별도로 지정하지 않으면 배열의 인덱스가 key 값으로 사용됩니다. 여기서는 name 값을 고유 키로 사용했습니다.
keyExtractor={item => item.name}
아래는 FlatList를 구현한 전체 코드입니다.
import React from "react";
import { FlatList, Text, View, StyleSheet, StatusBar } from "react-native";
export default class App extends React.Component {
constructor() {
super();
this.state = {
data: [
{ name: "Javascript Frameworks", isTitle: true },
{ name: "Angular", isTitle: false },
{ name: "ReactJS", isTitle: false },
{ name: "VueJS", isTitle: false },
{ name: "ReactNative", isTitle: false },
{ name: "PHP Frameworks", isTitle: true },
{ name: "Laravel", isTitle: false },
{ name: "CodeIgniter", isTitle: false },
{ name: "CakePHP", isTitle: false },
{ name: "Symfony", isTitle: false }
],
stickyHeaderIndices: []
};
}
renderItem = ({ item }) => {
return (
<View style={styles.item}>
<Text style={{ fontWeight: (item.isTitle) ? "bold" : "",
color: (item.isTitle) ? "red" : "gray" }}>
{item.name}
</Text>
</View>
);
};
render() {
return (
<View style={styles.container}>
<FlatList data={this.state.data} renderItem={this.renderItem}
keyExtractor={item => item.name}
stickyHeaderIndices={this.state.stickyHeaderIndices} />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: StatusBar.currentHeight || 0,
},
item: {
margin: 10,
padding: 20,
marginVertical: 8,
marginHorizontal: 16,
}
});
실행 결과
위 코드를 실행하면 카테고리 제목(빨간색 굵은 글씨)과 프레임워크 이름들이 세로 방향 리스트로 정렬되어 표시됩니다.
예제 2: FlatList 항목을 가로로 표시하기
FlatList 항목을 가로 방향으로 표시하고 싶다면 컴포넌트에 horizontal={true} props만 추가하면 됩니다.
import React from "react";
import { FlatList, Text, View, StyleSheet, StatusBar } from "react-native";
export default class App extends React.Component {
constructor() {
super();
this.state = {
data: [
{ name: "Javascript Frameworks", isTitle: true },
{ name: "Angular", isTitle: false },
{ name: "ReactJS", isTitle: false },
{ name: "VueJS", isTitle: false },
{ name: "ReactNative", isTitle: false },
{ name: "PHP Frameworks", isTitle: true },
{ name: "Laravel", isTitle: false },
{ name: "CodeIgniter", isTitle: false },
{ name: "CakePHP", isTitle: false },
{ name: "Symfony", isTitle: false }
],
stickyHeaderIndices: []
};
}
renderItem = ({ item }) => {
return (
<View style={styles.item}>
<Text style={{ fontWeight: (item.isTitle) ? "bold" : "",
color: (item.isTitle) ? "red" : "gray" }}>
{item.name}
</Text>
</View>
);
};
render() {
return (
<View style={styles.container}>
<FlatList horizontal={true} data={this.state.data}
renderItem={this.renderItem}
keyExtractor={item => item.name}
stickyHeaderIndices={this.state.stickyHeaderIndices} />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 100,
},
item: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
padding: 30,
margin: 2,
borderColor: '#2a4944',
borderWidth: 1,
height: 100,
backgroundColor: '#d2f7f1'
}
});
실행 결과
horizontal 속성을 true로 설정하면 항목들이 좌우로 스크롤되는 가로형 리스트(carousel 형태)로 표시됩니다. 배경색과 테두리 스타일을 추가해 각 항목을 카드처럼 꾸밀 수도 있습니다.
마무리
FlatList는 React Native에서 대량의 데이터를 성능 저하 없이 렌더링할 수 있는 필수 컴포넌트입니다. data와 renderItem 두 가지 핵심 props만 이해하면 기본적인 리스트를 바로 구현할 수 있으며, horizontal, ListHeaderComponent, ListEmptyComponent 등 다양한 props를 조합하면 헤더·푸터, 빈 목록 처리, 가로 스크롤 등 실무에서 필요한 거의 모든 리스트 UI를 손쉽게 완성할 수 있습니다.