기본적이고 단순한 리스트를 렌더링하기 위한 고성능 인터페이스로, 가장 유용한 기능들을 제공한다:
- 완전한 크로스 플랫폼 지원
- 선택적 수평 모드
- 구성 가능한 가시성 콜백
- 헤더 지원
- 푸터 지원
- 구분선 지원
- 당겨서 새로고침
- 스크롤 로딩
- ScrollToIndex 지원
- 다중 컬럼 지원
섹션 지원이 필요하다면 <SectionList>
를 사용한다.
- TypeScript
- JavaScript
여러 컬럼을 렌더링하려면 numColumns
prop을 사용한다. flexWrap
레이아웃 대신 이 방식을 사용하면 아이템 높이 로직과의 충돌을 방지할 수 있다.
아래는 더 복잡한 선택 가능한 예제이다.
extraData={selectedId}
를FlatList
에 전달하면 상태가 변경될 때FlatList
가 리렌더링되도록 보장한다. 이 prop을 설정하지 않으면FlatList
는PureComponent
이기 때문에 prop 비교 시 변경 사항이 없어 리렌더링이 필요하다는 것을 알지 못한다.keyExtractor
는 리스트가 기본key
속성 대신id
를 React 키로 사용하도록 지시한다.
- TypeScript
- JavaScript
이것은 <VirtualizedList>
를 편리하게 래핑한 것이므로, 여기에 명시적으로 나열되지 않은 props(또는 <ScrollView>
의 props)를 상속받는다. 단, 다음과 같은 주의사항이 있다:
- 내용이 렌더링 윈도우를 벗어나면 내부 상태가 유지되지 않는다. 모든 데이터가 아이템 데이터 또는 Flux, Redux, Relay와 같은 외부 저장소에 캡처되었는지 확인한다.
- 이 컴포넌트는
PureComponent
이므로props
가 얕은 비교에서 동일하면 리렌더링되지 않는다.renderItem
함수가 의존하는 모든 것이 업데이트 후===
이 아닌 prop(예:extraData
)으로 전달되었는지 확인한다. 그렇지 않으면 UI가 변경되지 않을 수 있다. 여기에는data
prop과 부모 컴포넌트 상태가 포함된다. - 메모리를 제한하고 부드러운 스크롤을 가능하게 하기 위해 내용은 비동기적으로 오프스크린에서 렌더링된다. 이는 채우기 속도보다 빠르게 스크롤할 수 있고 잠시 빈 내용을 볼 수 있음을 의미한다. 이는 각 애플리케이션의 필요에 맞게 조정할 수 있는 트레이드오프이며, 우리는 이를 개선하기 위해 노력하고 있다.
- 기본적으로 리스트는 각 아이템의
key
prop을 찾아 React 키로 사용한다. 또는 커스텀keyExtractor
prop을 제공할 수 있다.
참조
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
와 같은 추가 메타데이터를 제공한다. 또한 highlight
와 unhighlight
(이들은 highlighted: boolean
prop을 설정)가 사용 사례에 충분하지 않을 때, 선행 또는 후행 구분자(separator)의 렌더링을 변경하기 위해 어떤 prop이든 설정할 수 있는 separators.updateProps
함수도 제공한다.
타입 |
---|
function |
item
(Object): 렌더링될data
의 아이템index
(number):data
배열에서 이 아이템에 해당하는 인덱스separators
(Object)highlight
(Function)unhighlight
(Function)updateProps
(Function)select
(enum('leading', 'trailing'))newProps
(Object)
사용 예시:
<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 />
)를 사용할 수 있다.
타입 |
---|
component, element |
ListFooterComponentStyle
ListFooterComponent
내부 View를 위한 스타일링 정보를 담고 있다.
타입 |
---|
View 스타일 |
ListHeaderComponent
모든 아이템 상단에 렌더링된다. React 컴포넌트(예: SomeComponent
)나 React 엘리먼트(예: <SomeComponent />
) 형태로 사용할 수 있다.
타입 |
---|
컴포넌트, 엘리먼트 |
ListHeaderComponentStyle
ListHeaderComponent
내부 View를 위한 스타일링을 정의한다.
타입 |
---|
View 스타일 |
columnWrapperStyle
numColumns > 1
인 경우, 여러 아이템으로 구성된 행에 적용할 수 있는 커스텀 스타일이다. 이 속성은 선택적으로 사용할 수 있다.
타입 |
---|
View Style |
extraData
리스트를 리렌더링하도록 지시하는 마커 속성이다. (PureComponent
를 구현하기 때문) 만약 renderItem
, Header, Footer 등의 함수가 data
prop 외부의 어떤 것에 의존한다면, 이곳에 추가하고 불변하게 처리한다.
타입 |
---|
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
를 지정한 경우, 오프셋 계산에 구분자의 길이(높이 또는 너비)를 포함해야 한다.
타입 |
---|
함수 |
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
프로퍼티도 올바르게 설정해야 한다.
타입 |
---|
function |
onViewableItemsChanged
viewabilityConfig
속성에 정의된 대로 행의 가시성이 변경될 때 호출된다.
타입 |
---|
(callback: {changed: ViewToken[], viewableItems: ViewToken[]} => void; |
progressViewOffset
로딩 인디케이터가 정확하게 표시되기 위해 오프셋이 필요할 때 이 값을 설정한다.
타입 |
---|
number |
refreshing
새로운 데이터를 갱신하는 동안 이 값을 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
아이템이 실제로 보여지는 최소 시간(밀리초 단위)을 지정한다. 이 시간 동안 아이템이 화면에 노출되어야 뷰어빌리티 콜백이 실행된다. 이 값을 높게 설정하면, 스크롤을 멈추지 않고 빠르게 지나갈 경우 해당 콘텐츠를 보여지는 것으로 간주하지 않는다.
viewAreaCoveragePercentThreshold
뷰포트에서 부분적으로 가려진 아이템이 '보여지는' 것으로 간주되려면, 뷰포트의 몇 퍼센트가 해당 아이템으로 덮여 있어야 하는지를 나타내는 값이다. 범위는 0에서 100 사이이며, 완전히 보이는 아이템은 항상 '보여지는' 것으로 간주된다. 값이 0이면 뷰포트에 단 하나의 픽셀만 보여도 아이템이 보여지는 것으로 간주되고, 값이 100이면 아이템이 완전히 보이거나 뷰포트 전체를 덮어야만 보여지는 것으로 간주된다.
itemVisiblePercentThreshold
viewAreaCoveragePercentThreshold
와 유사하지만, 뷰어블 영역을 얼마나 차지하는지가 아니라 아이템 자체가 얼마나 보이는지를 고려한다.
사용자가 스크롤하거나 렌더링 후 recordInteraction
을 호출하기 전까지는 어떤 것도 화면에 보이는 상태로 간주하지 않는다.
viewabilityConfigCallbackPairs
ViewabilityConfig
와 onViewableItemsChanged
의 쌍으로 이루어진 리스트이다. 특정 ViewabilityConfig
의 조건이 충족될 때, 해당하는 onViewableItemsChanged
가 호출된다. 자세한 플로우 타입과 문서는 ViewabilityHelper.js
를 참고한다.
타입 |
---|
ViewabilityConfigCallbackPair의 배열 |
메서드
flashScrollIndicators()
flashScrollIndicators();
스크롤 인디케이터를 잠시 동안 표시한다.
getNativeScrollRef()
getNativeScrollRef(): React.ElementRef<typeof ScrollViewComponent>;
기본 스크롤 컴포넌트에 대한 참조를 제공한다.
getScrollResponder()
getScrollResponder(): ScrollResponderMixin;
기본 스크롤 응답자에 대한 핸들을 제공한다.
getScrollableNode()
getScrollableNode(): any;
기본 스크롤 노드에 대한 핸들을 제공한다.
scrollToEnd()
scrollToEnd(params?: {animated?: boolean});
컨텐츠의 끝까지 스크롤한다. getItemLayout
속성이 없으면 부드럽지 않을 수 있다.
인자:
이름 | 타입 |
---|---|
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
속성을 지정하지 않으면 렌더링 윈도우 외부의 위치로 스크롤할 수 없다.
매개변수:
이름 | 타입 |
---|---|
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
이다.