FlatList
기본적이고 단순한 리스트를 렌더링하기 위한 고성능 인터페이스로, 가장 유용한 기능을 지원한다:
- 완전한 크로스 플랫폼 지원
- 선택 가능한 수평 모드
- 구성 가능한 가시성 콜백
- 헤더 지원
- 푸터 지원
- 구분자 지원
- 당겨서 새로고침
- 스크롤 로딩
- ScrollToIndex 지원
- 다중 컬럼 지원
섹션 지원이 필요하다면 <SectionList>
를 사용한다.
예제
- TypeScript
- JavaScript
여러 컬럼을 렌더링하려면 numColumns
속성을 사용한다. 이 방식은 flexWrap
레이아웃 대신 사용해 아이템 높이 로직과의 충돌을 방지할 수 있다.
아래는 더 복잡한 선택 가능한 예제다.
extraData={selectedId}
를FlatList
에 전달해 상태가 변경될 때FlatList
가 리렌더링되도록 한다. 이 속성을 설정하지 않으면FlatList
는PureComponent
이기 때문에 속성 비교에서 변경 사항을 감지하지 못해 아이템을 리렌더링하지 않는다.keyExtractor
는 리스트가 기본key
속성 대신id
를 React 키로 사용하도록 지시한다.
- TypeScript
- JavaScript
이것은 <VirtualizedList>
를 편리하게 래핑한 것이므로, 여기에 명시적으로 나열되지 않은 속성(또는 <ScrollView>
의 속성)을 상속받는다. 단, 다음과 같은 주의사항이 있다:
- 컨텐츠가 렌더링 윈도우를 벗어나 스크롤되면 내부 상태가 유지되지 않는다. 모든 데이터가 아이템 데이터나 Flux, Redux, Relay와 같은 외부 저장소에 캡처되어 있는지 확인한다.
- 이 컴포넌트는
PureComponent
이므로props
가 얕은 비교에서 동일하면 리렌더링하지 않는다.renderItem
함수가 의존하는 모든 것이 업데이트 후===
이 아닌 속성(예:extraData
)으로 전달되는지 확인한다. 그렇지 않으면 UI가 변경 사항에 반응하지 않을 수 있다. 이는data
속성과 부모 컴포넌트의 상태를 포함한다. - 메모리를 제한하고 부드러운 스크롤을 가능하게 하기 위해 컨텐츠는 오프스크린에서 비동기적으로 렌더링된다. 이는 채우는 속도보다 빠르게 스크롤할 경우 일시적으로 빈 컨텐츠를 볼 수 있다는 것을 의미한다. 이는 각 애플리케이션의 필요에 따라 조정할 수 있는 트레이드오프이며, 이를 개선하기 위해 내부적으로 작업 중이다.
- 기본적으로 리스트는 각 아이템의
key
속성을 찾아 React 키로 사용한다. 또는 커스텀keyExtractor
속성을 제공할 수 있다.
참고 자료
Props
VirtualizedList Props
VirtualizedList Props를 상속받는다.
필수 renderItem
renderItem({
item: ItemT,
index: number,
separators: {
highlight: () => void;
unhighlight: () => void;
updateProps: (select: 'leading' | 'trailing', newProps: any) => void;
}
}): JSX.Element;
data
에서 아이템을 가져와 리스트로 렌더링한다.
필요한 경우 index
와 같은 추가 메타데이터를 제공하며, 더 일반적인 separators.updateProps
함수를 통해 리딩 또는 트레일링 구분자의 렌더링을 변경할 수 있다. highlight
와 unhighlight
(이들은 highlighted: boolean
prop을 설정한다)가 충분하지 않은 경우에 유용하다.
타입 |
---|
함수 |
item
(객체): 렌더링될data
의 아이템.index
(숫자):data
배열에서 이 아이템에 해당하는 인덱스.separators
(객체)highlight
(함수)unhighlight
(함수)updateProps
(함수)select
(enum('leading', 'trailing'))newProps
(객체)
사용 예시:
<FlatList
ItemSeparatorComponent={
Platform.OS !== 'android' &&
(({highlighted}) => (
<View
style={[style.separator, highlighted && {marginLeft: 0}]}
/>
))
}
data={[{title: 'Title Text', key: 'item1'}]}
renderItem={({item, index, separators}) => (
<TouchableHighlight
key={item.key}
onPress={() => this._onPress(item)}
onShowUnderlay={separators.highlight}
onHideUnderlay={separators.unhighlight}>
<View style={{backgroundColor: 'white'}}>
<Text>{item.title}</Text>
</View>
</TouchableHighlight>
)}
/>
필수 data
렌더링할 아이템들의 배열(또는 배열과 유사한 리스트). 다른 데이터 타입을 사용하려면 VirtualizedList
를 직접 타겟팅해야 한다.
타입 |
---|
ArrayLike |
ItemSeparatorComponent
각 아이템 사이에 렌더링되지만, 맨 위나 맨 아래에는 렌더링되지 않는다. 기본적으로 highlighted
와 leadingItem
props가 제공된다. renderItem
은 separators.highlight
/unhighlight
를 제공하며, 이는 highlighted
prop을 업데이트한다. 또한 separators.updateProps
를 사용해 커스텀 props를 추가할 수도 있다. React 컴포넌트(예: SomeComponent
) 또는 React 엘리먼트(예: <SomeComponent />
)로 사용할 수 있다.
타입 |
---|
컴포넌트, 함수, 엘리먼트 |
ListEmptyComponent
리스트가 비어 있을 때 렌더링되는 컴포넌트다. React 컴포넌트(예: SomeComponent
)나 React 엘리먼트(예: <SomeComponent />
) 형태로 사용할 수 있다.
타입 |
---|
컴포넌트, 엘리먼트 |
ListFooterComponent
모든 아이템 하단에 렌더링된다. React 컴포넌트(예: SomeComponent
) 또는 React 엘리먼트(예: <SomeComponent />
)로 사용할 수 있다.
타입 |
---|
컴포넌트, 엘리먼트 |
ListFooterComponentStyle
ListFooterComponent
내부 View에 적용할 스타일을 정의한다.
타입 |
---|
View 스타일 |
ListHeaderComponent
모든 아이템 상단에 렌더링되는 컴포넌트이다. React 컴포넌트(예: SomeComponent
)나 React 엘리먼트(예: <SomeComponent />
)로 지정할 수 있다.
타입 |
---|
component, element |
ListHeaderComponentStyle
ListHeaderComponent
내부 View에 대한 스타일을 정의한다.
타입 |
---|
View 스타일 |
columnWrapperStyle
numColumns > 1
일 때 생성되는 다중 아이템 행에 적용할 수 있는 커스텀 스타일을 지정한다.
타입 |
---|
View Style |
extraData
리스트가 리렌더링되도록 지시하는 마커 프로퍼티다 (PureComponent
를 구현하기 때문). renderItem
, Header, Footer 등의 함수가 data
프로퍼티 외부의 어떤 것에 의존한다면, 여기에 넣고 불변하게 처리한다.
타입 |
---|
any |
getItemLayout
(data, index) => {length: number, offset: number, index: number}
getItemLayout
은 동적 콘텐츠의 크기를 미리 알고 있을 때, 측정 과정을 건너뛸 수 있게 해주는 선택적 최적화 기능이다. 고정된 크기의 아이템이 있는 경우 getItemLayout
을 사용하면 효율적이다. 예를 들어:
getItemLayout={(data, index) => (
{length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index}
)}
getItemLayout
을 추가하면 수백 개의 아이템으로 이루어진 리스트의 성능을 크게 향상시킬 수 있다. ItemSeparatorComponent
를 지정한 경우, 오프셋 계산에 구분자의 길이(높이 또는 너비)를 포함해야 한다.
타입 |
---|
function |
horizontal
true
로 설정하면 아이템을 세로로 쌓는 대신 가로로 나란히 렌더링한다.
타입 |
---|
boolean |
initialNumToRender
초기 렌더링 시 화면에 표시할 항목 수를 설정한다. 이 값은 화면을 채우기에 충분한 수준이어야 하지만 너무 많지는 않아야 한다. 이 항목들은 스크롤 상단으로 이동할 때의 성능을 높이기 위해 윈도우 렌더링 과정에서 언마운트되지 않는다.
타입 | 기본값 |
---|---|
number | 10 |
initialScrollIndex
처음 아이템이 아닌 initialScrollIndex
에서 시작한다. 이 설정은 첫 번째 initialNumToRender
아이템을 항상 렌더링하는 "맨 위로 스크롤" 최적화를 비활성화하고, 초기 인덱스에서 시작하는 아이템을 즉시 렌더링한다. 이 기능을 사용하려면 getItemLayout
을 구현해야 한다.
타입 |
---|
number |
inverted
스크롤 방향을 반대로 설정한다. -1
스케일 변환을 사용한다.
타입 |
---|
boolean |
keyExtractor
(item: ItemT, index: number) => string;
주어진 아이템과 인덱스를 기반으로 고유한 키를 추출하는 데 사용한다. 이 키는 캐싱과 아이템 재정렬을 추적하기 위한 React 키로 활용된다. 기본 추출기는 item.key
, item.id
를 순서대로 확인하고, 둘 다 없는 경우 React와 마찬가지로 인덱스를 사용한다.
타입 |
---|
함수 |
numColumns
numColumns
는 horizontal={false}
일 때만 여러 컬럼을 렌더링할 수 있으며, flexWrap
레이아웃처럼 지그재그 형태로 배치된다. 모든 아이템의 높이가 동일해야 하며, masonry 레이아웃은 지원하지 않는다.
타입 |
---|
number |
onRefresh
() => void;
이 함수를 제공하면 "당겨서 새로고침(Pull to Refresh)" 기능을 위해 표준 RefreshControl이 추가된다. 이때 refreshing
prop도 올바르게 설정해야 한다.
타입 |
---|
function |
onViewableItemsChanged
행의 가시성이 변경될 때 호출되는 콜백 함수. 이 동작은 viewabilityConfig
prop에 정의된 기준에 따라 결정된다.
타입 |
---|
(callback: {changed: ViewToken[], viewableItems: ViewToken[]} => void; |
progressViewOffset
로딩 인디케이터가 올바르게 표시되도록 오프셋이 필요할 때 이 값을 설정한다.
타입 |
---|
number |
refreshing
새로운 데이터를 갱신(refresh)하기 위해 기다리는 동안 이 값을 true로 설정한다.
타입 |
---|
boolean |
removeClippedSubviews
이 옵션은 큰 리스트의 스크롤 성능을 향상시킬 수 있다. 안드로이드에서는 기본값이 true
로 설정되어 있다.
주의: 특정 상황에서 버그(콘텐츠 누락)가 발생할 수 있으므로 주의해서 사용해야 한다.
타입 |
---|
boolean |
viewabilityConfig
자세한 Flow 타입과 문서는 ViewabilityHelper.js
에서 확인할 수 있다.
타입 |
---|
ViewabilityConfig |
viewabilityConfig
는 ViewabilityConfig
타입을 받는다. 이 타입은 다음과 같은 속성을 가진 객체이다.
속성 | 타입 |
---|---|
minimumViewTime | number |
viewAreaCoveragePercentThreshold | number |
itemVisiblePercentThreshold | number |
waitForInteraction | boolean |
viewAreaCoveragePercentThreshold
또는 itemVisiblePercentThreshold
중 적어도 하나는 필수로 설정해야 한다. 이 설정은 constructor
에서 해야 하며, 그렇지 않으면 다음과 같은 오류가 발생할 수 있다 (참조):
Error: Changing viewabilityConfig on the fly is not supported
constructor (props) {
super(props)
this.viewabilityConfig = {
waitForInteraction: true,
viewAreaCoveragePercentThreshold: 95
}
}
<FlatList
viewabilityConfig={this.viewabilityConfig}
...
minimumViewTime
minimumViewTime은 viewability 콜백이 실행되기 전에 아이템이 실제로 보여야 하는 최소 시간(밀리초 단위)을 의미한다. 이 값을 크게 설정하면, 스크롤을 멈추지 않고 빠르게 지나가는 콘텐츠는 '보이는 상태'로 간주되지 않는다.
viewAreaCoveragePercentThreshold
뷰포트에서 부분적으로 가려진 아이템이 "보이는 상태"로 간주되기 위해 차지해야 하는 비율을 나타낸다. 범위는 0부터 100까지다. 완전히 보이는 아이템은 항상 보이는 상태로 간주된다. 값이 0이면 뷰포트에 단 하나의 픽셀만 보여도 아이템이 보이는 상태로 판단된다. 반면 값이 100이면 아이템이 완전히 보이거나 전체 뷰포트를 차지해야 보이는 상태로 간주된다.
itemVisiblePercentThreshold
viewAreaCoveragePercentThreshold
와 유사하지만, 뷰 영역에서 차지하는 비율 대신 아이템이 얼마나 보이는지를 기준으로 한다.
waitForInteraction
사용자가 스크롤하거나 렌더링 후 recordInteraction
이 호출되기 전까지는 아무것도 보이는 상태로 간주되지 않는다.
viewabilityConfigCallbackPairs
ViewabilityConfig
와 onViewableItemsChanged
의 쌍으로 이루어진 리스트이다. 특정 ViewabilityConfig
의 조건이 충족되면, 해당하는 onViewableItemsChanged
가 호출된다. 자세한 플로우 타입과 추가 문서는 ViewabilityHelper.js
를 참고한다.
타입 |
---|
ViewabilityConfigCallbackPair 배열 |
메서드
flashScrollIndicators()
flashScrollIndicators();
스크롤 인디케이터를 잠시 동안 표시한다.
getNativeScrollRef()
getNativeScrollRef(): React.ElementRef<typeof ScrollViewComponent>;
스크롤 컴포넌트의 실제 참조를 제공한다.
getScrollResponder()
getScrollResponder(): ScrollResponderMixin;
기본 스크롤 응답자(responder)에 대한 핸들러를 제공한다.
getScrollableNode()
getScrollableNode(): any;
스크롤 가능한 노드에 대한 핸들을 제공한다.
scrollToEnd()
scrollToEnd(params?: {animated?: boolean});
컨텐츠의 끝까지 스크롤한다. getItemLayout
prop 없이 사용하면 부드럽지 않을 수 있다.
매개변수:
이름 | 타입 |
---|---|
params | object |
유효한 params
키는 다음과 같다:
- 'animated' (boolean) - 스크롤 시 애니메이션을 사용할지 여부. 기본값은
true
이다.
scrollToIndex()
scrollToIndex: (params: {
index: number;
animated?: boolean;
viewOffset?: number;
viewPosition?: number;
});
지정된 인덱스에 위치한 아이템을 뷰포트 내에서 스크롤하여 보여준다. viewPosition
값이 0이면 아이템을 상단에, 1이면 하단에, 0.5면 중앙에 위치시킨다.
참고:
getItemLayout
프로퍼티를 지정하지 않으면 렌더링된 영역 밖의 위치로 스크롤할 수 없다.
매개변수:
이름 | 타입 |
---|---|
params 필수 | object |
유효한 params
키는 다음과 같다:
- 'animated' (boolean) - 스크롤 시 애니메이션을 적용할지 여부. 기본값은
true
. - 'index' (number) - 스크롤할 대상 인덱스. 필수.
- 'viewOffset' (number) - 최종 목표 위치에서 고정된 픽셀 수만큼 오프셋을 적용.
- 'viewPosition' (number) -
0
은 인덱스로 지정된 아이템을 상단에,1
은 하단에,0.5
는 중앙에 위치시킨다.
scrollToItem()
scrollToItem(params: {
animated?: ?boolean,
item: Item,
viewPosition?: number,
});
데이터를 선형으로 스캔해야 하므로 가능한 경우 scrollToIndex
를 대신 사용한다.
주의:
getItemLayout
prop을 지정하지 않으면 렌더링 윈도우 외부의 위치로 스크롤할 수 없다.
매개변수:
이름 | 타입 |
---|---|
params 필수 | object |
유효한 params
키는 다음과 같다:
- 'animated' (boolean) - 스크롤 시 애니메이션을 적용할지 여부. 기본값은
true
. - 'item' (object) - 스크롤할 대상 항목. 필수.
- 'viewPosition' (number)
scrollToOffset()
scrollToOffset(params: {
offset: number;
animated?: boolean;
});
리스트 내 특정 컨텐츠 픽셀 오프셋으로 스크롤한다.
매개변수:
이름 | 타입 |
---|---|
params 필수 | object |
유효한 params
키는 다음과 같다:
- 'offset' (number) - 스크롤할 오프셋.
horizontal
이 true인 경우 오프셋은 x값이고, 그 외의 경우 오프셋은 y값이다. 필수. - 'animated' (boolean) - 스크롤 시 애니메이션을 사용할지 여부. 기본값은
true
.