高性能的簡單列表組件溅呢,支持下面這些常用的功能:
- 完全跨平臺披蕉。
- 支持水平布局模式。
- 行組件顯示或隱藏時可配置回調(diào)事件伞访。
- 支持單獨的頭部組件掂骏。
- 支持單獨的尾部組件。
- 支持自定義行間分隔線厚掷。
- 支持下拉刷新弟灼。
- 支持上拉加載。
- 支持跳轉(zhuǎn)到指定行(ScrollToIndex)冒黑。
如果需要分組/類/區(qū)(section)田绑,請使用<SectionList>
.
一個最簡單的例子:
<FlatList
data={[{key: 'a'}, {key: 'b'}]}
renderItem={({item}) => <Text>{item.key}</Text>}
/>
下面是一個較復(fù)雜的例子,其中演示了如何利用PureComponent
來進(jìn)一步優(yōu)化性能和減少 bug 產(chǎn)生的可能(以下這段文字需要你深刻理解 shouldComponentUpdate 的機(jī)制抡爹,以及 Component 和 PureComponent 的不同掩驱,所以如果不了解就先跳過吧)。
- 對于
MyListItem
組件來說,其onPressItem
屬性使用箭頭函數(shù)而非 bind 的方式進(jìn)行綁定欧穴,使其不會在每次列表重新 render 時生成一個新的函數(shù)民逼,從而保證了 props 的不變性(當(dāng)然前提是id
、selected
和title
也沒變)涮帘,不會觸發(fā)自身無謂的重新 render拼苍。換句話說,如果你是用 bind 來綁定onPressItem
调缨,每次都會生成一個新的函數(shù)疮鲫,導(dǎo)致 props 在===
比較時返回 false,從而觸發(fā)自身的一次不必要的重新 render弦叶。 - 給
FlatList
指定extraData={this.state}
屬性俊犯,是為了保證state.selected
變化時,能夠正確觸發(fā)FlatList
的更新湾蔓。如果不指定此屬性瘫析,則FlatList
不會觸發(fā)更新,因為它是一個PureComponent
默责,其 props 在===
比較中沒有變化則不會觸發(fā)更新贬循。 -
keyExtractor
屬性指定使用 id 作為列表每一項的 key。
class MyListItem extends React.PureComponent {
_onPress = () => {
this.props.onPressItem(this.props.id);
};
render() {
const textColor = this.props.selected ? "red" : "black";
return (
<TouchableOpacity onPress={this._onPress}>
<View>
<Text style={{ color: textColor }}>
{this.props.title}
</Text>
</View>
</TouchableOpacity>
);
}
}
class MultiSelectList extends React.PureComponent {
state = {selected: (new Map(): Map<string, boolean>)};
_keyExtractor = (item, index) => item.id;
_onPressItem = (id: string) => {
// updater functions are preferred for transactional updates
this.setState((state) => {
// copy the map rather than modifying state.
const selected = new Map(state.selected);
selected.set(id, !selected.get(id)); // toggle
return {selected};
});
};
_renderItem = ({item}) => (
<MyListItem
id={item.id}
onPressItem={this._onPressItem}
selected={!!this.state.selected.get(item.id)}
title={item.title}
/>
);
render() {
return (
<FlatList
data={this.props.data}
extraData={this.state}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
/>
);
}
}
本組件實質(zhì)是基于<VirtualizedList>
組件的封裝桃序,繼承了其所有 props(也包括所有<ScrollView>
)的 props)杖虾,但在本文檔中沒有列出。此外還有下面這些需要注意的事項:
- 當(dāng)某行滑出渲染區(qū)域之外后媒熊,其內(nèi)部狀態(tài)將不會保留奇适。請確保你在行組件以外的地方保留了數(shù)據(jù)。
- 本組件繼承自
PureComponent
而非通常的Component
芦鳍,這意味著如果其props
在淺比較
中是相等的嚷往,則不會重新渲染。所以請先檢查你的renderItem
函數(shù)所依賴的props
數(shù)據(jù)(包括data
屬性以及可能用到的父組件的 state)柠衅,如果是一個引用類型(Object 或者數(shù)組都是引用類型)皮仁,則需要先修改其引用地址(比如先復(fù)制到一個新的 Object 或者數(shù)組中),然后再修改其值菲宴,否則界面很可能不會刷新贷祈。(譯注:這一段不了解的朋友建議先學(xué)習(xí)下js 中的基本類型和引用類型。) - 為了優(yōu)化內(nèi)存占用同時保持滑動的流暢喝峦,列表內(nèi)容會在屏幕外異步繪制势誊。這意味著如果用戶滑動的速度超過渲染的速度,則會先看到空白的內(nèi)容谣蠢。這是為了優(yōu)化不得不作出的妥協(xié)粟耻,你可以根據(jù)自己的需求調(diào)整相應(yīng)的參數(shù)查近,而我們也在設(shè)法持續(xù)改進(jìn)。
- 默認(rèn)情況下每行都需要提供一個不重復(fù)的 key 屬性挤忙。你也可以提供一個
keyExtractor
函數(shù)來生成 key嗦嗡。
本組件如果嵌套在其他同滾動方向的 FlatList 中,則不會繼承ScrollView 的 Props饭玲。
文檔
Props
renderItem
renderItem({ item: Object, index: number, separators: { highlight: Function, unhighlight: Function, updateProps: Function(select: string, newProps: Object) } }) => ?React.Element
從data
中挨個取出數(shù)據(jù)并渲染到列表中。
Provides additional metadata like index
if you need it, as well as a more generic separators.updateProps
function which let you set whatever props you want to change the rendering of either the leading separator or trailing separator in case the more common highlight
and unhighlight
(which set the highlighted: boolean
prop) are insufficient for your use case.
類型 | 必填 |
---|---|
function | 是 |
示例:
<FlatList
ItemSeparatorComponent={Platform.OS !== 'android' && ({highlighted}) => (
<View style={[style.separator, highlighted && {marginLeft: 0}]} />
)}
data={[{title: 'Title Text', key: 'item1'}]}
renderItem={({item, separators}) => (
<TouchableHighlight
onPress={() => this._onPress(item)}
onShowUnderlay={separators.highlight}
onHideUnderlay={separators.unhighlight}>
<View style={{backgroundColor: 'white'}}>
<Text>{item.title}</Text>
</View>
</TouchableHighlight>
)}
/>
data
為了簡化起見叁执,data 屬性目前只支持普通數(shù)組茄厘。如果需要使用其他特殊數(shù)據(jù)結(jié)構(gòu),例如 immutable 數(shù)組谈宛,請直接使用更底層的VirtualizedList
組件次哈。
類型 | 必填 |
---|---|
array | 是 |
ItemSeparatorComponent
行與行之間的分隔線組件。不會出現(xiàn)在第一行之前和最后一行之后吆录。 By default, highlighted
and leadingItem
props are provided. renderItem
provides separators.highlight
/unhighlight
which will update the highlighted
prop, but you can also add custom props with separators.updateProps
.
類型 | 必填 |
---|---|
component | 否 |
ListEmptyComponent
列表為空時渲染該組件窑滞。可以是 React Component, 也可以是一個 render 函數(shù)恢筝,或者渲染好的 element哀卫。
類型 | 必填 |
---|---|
component, function, element | 否 |
ListFooterComponent
尾部組件∏瞬郏可以是 React Component, 也可以是一個 render 函數(shù)此改,或者渲染好的 element。
類型 | 必填 |
---|---|
component, function, element | 否 |
ListHeaderComponent
頭部組件侄柔」部校可以是 React Component, 也可以是一個 render 函數(shù),或者渲染好的 element暂题。
類型 | 必填 |
---|---|
component, function, element | 否 |
columnWrapperStyle
如果設(shè)置了多列布局(即將numColumns
值設(shè)為大于 1 的整數(shù))移剪,則可以額外指定此樣式作用在每行容器上。
類型 | 必填 |
---|---|
style object | 否 |
extraData
如果有除data
以外的數(shù)據(jù)用在列表中(不論是用在renderItem
還是頭部或者尾部組件中)薪者,請在此屬性中指定纵苛。同時此數(shù)據(jù)在修改時也需要先修改其引用地址(比如先復(fù)制到一個新的 Object 或者數(shù)組中),然后再修改其值啸胧,否則界面很可能不會刷新赶站。
類型 | 必填 |
---|---|
any | 否 |
getItemLayout
(data, index) => {length: number, offset: number, index: number}
getItemLayout
是一個可選的優(yōu)化,用于避免動態(tài)測量內(nèi)容尺寸的開銷纺念,不過前提是你可以提前知道內(nèi)容的高度贝椿。如果你的行高是固定的,getItemLayout
用起來就既高效又簡單陷谱,類似下面這樣:
getItemLayout={(data, index) => (
{length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index}
)}
對于元素較多的列表(幾百行)來說烙博,添加getItemLayout
可以極大地提高性能瑟蜈。注意如果你指定了ItemSeparatorComponent
,請把分隔線的尺寸也考慮到 offset 的計算之中渣窜。
類型 | 必填 |
---|---|
function | 否 |
horizontal
設(shè)置為 true 則變?yōu)樗讲季帜J健?/p>
類型 | 必填 |
---|---|
boolean | 否 |
initialNumToRender
指定一開始渲染的元素數(shù)量铺根,最好剛剛夠填滿一個屏幕,這樣保證了用最短的時間給用戶呈現(xiàn)可見的內(nèi)容乔宿。注意這第一批次渲染的元素不會在滑動過程中被卸載位迂,這樣是為了保證用戶執(zhí)行返回頂部的操作時,不需要重新渲染首批元素详瑞。
類型 | 必填 |
---|---|
number | 否 |
initialScrollIndex
開始時屏幕頂端的元素是列表中的第 initialScrollIndex
個元素, 而不是第一個元素掂林。如果設(shè)置了這個屬性,則第一批initialNumToRender
范圍內(nèi)的元素不會再保留在內(nèi)存里坝橡,而是直接立刻渲染位于 <code>initialScrollIndex</code> 位置的元素泻帮。需要先設(shè)置 <code>getItemLayout</code> 屬性。
類型 | 必填 |
---|---|
number | 否 |
inverted
翻轉(zhuǎn)滾動方向计寇。實質(zhì)是將 scale 變換設(shè)置為-1锣杂。
類型 | 必填 |
---|---|
boolean | 否 |
keyExtractor
(item: object, index: number) => string;
此函數(shù)用于為給定的 item 生成一個不重復(fù)的 key。Key 的作用是使 React 能夠區(qū)分同類元素的不同個體番宁,以便在刷新時能夠確定其變化的位置元莫,減少重新渲染的開銷。若不指定此函數(shù)蝶押,則默認(rèn)抽取item.key
作為 key 值柒竞。若item.key
也不存在,則使用數(shù)組下標(biāo)播聪。
類型 | 必填 |
---|---|
function | 否 |
numColumns
多列布局只能在非水平模式下使用朽基,即必須是horizontal={false}
。此時組件內(nèi)元素會從左到右從上到下按 Z 字形排列离陶,類似啟用了flexWrap
的布局稼虎。組件內(nèi)元素必須是等高的——暫時還無法支持瀑布流布局。
類型 | 必填 |
---|---|
number | 否 |
onEndReached
(info: {distanceFromEnd: number}) => void
當(dāng)列表被滾動到距離內(nèi)容最底部不足onEndReachedThreshold
的距離時調(diào)用招刨。
類型 | 必填 |
---|---|
function | 否 |
onEndReachedThreshold
決定當(dāng)距離內(nèi)容最底部還有多遠(yuǎn)時觸發(fā)onEndReached
回調(diào)霎俩。注意此參數(shù)是一個比值而非像素單位。比如沉眶,0.5 表示距離內(nèi)容最底部的距離為當(dāng)前列表可見長度的一半時觸發(fā)打却。
類型 | 必填 |
---|---|
number | 否 |
onRefresh
() => void
如果設(shè)置了此選項,則會在列表頭部添加一個標(biāo)準(zhǔn)的RefreshControl
控件谎倔,以便實現(xiàn)“下拉刷新”的功能柳击。同時你需要正確設(shè)置refreshing
屬性。
類型 | 必填 |
---|---|
function | 否 |
onViewableItemsChanged
(info: {
viewableItems: array,
changed: array,
}) => void
在可見行元素變化時調(diào)用片习“齐龋可見范圍和變化頻率等參數(shù)的配置請設(shè)置viewabilityConfig
屬性蹬叭。
類型 | 必填 |
---|---|
function | 否 |
progressViewOffset
當(dāng)需要在指定的偏移處顯示加載指示器的時候,就可以設(shè)置這個值状知。
類型 | 必填 | 平臺 |
---|---|---|
number | 否 | Android |
legacyImplementation
May not have full feature parity and is meant for debugging and performance comparison.
類型 | 必填 |
---|---|
boolean | 否 |
refreshing
在等待加載新數(shù)據(jù)時將此屬性設(shè)為 true秽五,列表就會顯示出一個正在加載的符號。
類型 | 必填 |
---|---|
boolean | 否 |
removeClippedSubviews
對于大列表啟用本屬性可能可以提高性能饥悴。
注意:有些情況下會有 bug(比如內(nèi)容無法顯示)坦喘。請謹(jǐn)慎使用。
類型 | 必填 |
---|---|
boolean | 否 |
viewabilityConfig
請參考ViewabilityHelper.js
的源碼來了解具體的配置西设。
類型 | 必填 |
---|---|
ViewabilityConfig | 否 |
viewabilityConfig
takes a type ViewabilityConfig
an object with following properties
Property | Required | Type |
---|---|---|
minimumViewTime | No | number |
viewAreaCoveragePercentThreshold | No | number |
itemVisiblePercentThreshold | No | number |
waitForInteraction | No | boolean |
At least one of the viewAreaCoveragePercentThreshold
or itemVisiblePercentThreshold
is required. This needs to be done in the constructor
to avoid following error (ref):
Error: Changing viewabilityConfig on the fly is not supported`
constructor (props) {
super(props)
this.viewabilityConfig = {
waitForInteraction: true,
viewAreaCoveragePercentThreshold: 95
}
}
<FlatList
viewabilityConfig={this.viewabilityConfig}
...
minimumViewTime
Minimum amount of time (in milliseconds) that an item must be physically viewable before the viewability callback will be fired. A high number means that scrolling through content without stopping will not mark the content as viewable.
viewAreaCoveragePercentThreshold
Percent of viewport that must be covered for a partially occluded item to count as "viewable", 0-100. Fully visible items are always considered viewable. A value of 0 means that a single pixel in the viewport makes the item viewable, and a value of 100 means that an item must be either entirely visible or cover the entire viewport to count as viewable.
itemVisiblePercentThreshold
Similar to viewAreaPercentThreshold
, but considers the percent of the item that is visible, rather than the fraction of the viewable area it covers.
waitForInteraction
Nothing is considered viewable until the user scrolls or recordInteraction
is called after render.
viewabilityConfigCallbackPairs
List of ViewabilityConfig
/onViewableItemsChanged
pairs. A specific onViewableItemsChanged
will be called when its corresponding ViewabilityConfig
's conditions are met. 請參考ViewabilityHelper.js
的源碼來了解具體的配置起宽。
類型 | 必填 |
---|---|
array of ViewabilityConfigCallbackPair | 否 |
方法
scrollToEnd()
scrollToEnd([params]);
滾動到底部。如果不設(shè)置getItemLayout
屬性的話济榨,可能會比較卡。
參數(shù):
名稱 | 類型 | 必填 | 說明 |
---|---|---|---|
params | object | 否 | 看下面的說明 |
Valid params
keys are:
- 'animated' (boolean) - Whether the list should do an animation while scrolling. Defaults to
true
.
scrollToIndex()
scrollToIndex(params);
將位于指定位置的元素滾動到可視區(qū)的指定位置绿映,當(dāng)viewPosition
為 0 時將它滾動到屏幕頂部擒滑,為 1 時將它滾動到屏幕底部,為 0.5 時將它滾動到屏幕中央叉弦。
注意:如果不設(shè)置
getItemLayout
屬性的話丐一,無法跳轉(zhuǎn)到當(dāng)前渲染區(qū)域以外的位置。
參數(shù):
名稱 | 類型 | 必填 | 說明 |
---|---|---|---|
params | object | 是 | 看下面的說明 |
Valid params
keys are:
- 'animated' (boolean) - Whether the list should do an animation while scrolling. Defaults to
true
. - 'index' (number) - The index to scroll to. Required.
- 'viewOffset' (number) - A fixed number of pixels to offset the final target position. Required.
- 'viewPosition' (number) - A value of
0
places the item specified by index at the top,1
at the bottom, and0.5
centered in the middle.
scrollToItem()
scrollToItem(params);
這個方法會順序遍歷元素淹冰。盡可能使用scrollToIndex
代替库车。
注意:如果不設(shè)置
getItemLayout
屬性的話,無法跳轉(zhuǎn)到當(dāng)前渲染區(qū)域以外的位置樱拴。
參數(shù):
名稱 | 類型 | 必填 | 說明 |
---|---|---|---|
params | object | 是 | 看下面的說明 |
Valid params
keys are:
- 'animated' (boolean) - Whether the list should do an animation while scrolling. Defaults to
true
. - 'item' (object) - The item to scroll to. Required.
- 'viewPosition' (number)
scrollToOffset()
scrollToOffset(params);
滾動列表到指定的偏移(以像素為單位),等同于ScrollView
的scrollTo
方法。
參數(shù):
名稱 | 類型 | 必填 | 說明 |
---|---|---|---|
params | object | 是 | 看下面的說明 |
Valid params
keys are:
- 'offset' (number) - The offset to scroll to. In case of
horizontal
being true, the offset is the x-value, in any other case the offset is the y-value. Required. - 'animated' (boolean) - Whether the list should do an animation while scrolling. Defaults to
true
.
recordInteraction()
recordInteraction();
主動通知列表發(fā)生了一個事件曼振,以使列表重新計算可視區(qū)域侵状。比如說當(dāng)waitForInteractions
為 true 并且用戶沒有滾動列表時。一般在用戶點擊了列表項或發(fā)生了導(dǎo)航動作時調(diào)用正罢。
flashScrollIndicators()
flashScrollIndicators();
短暫地顯示滾動指示器阵漏。