React Native 中更優良的列表視圖
在我們於社群群組中發布搶先看公告後,你們許多人已經開始試用我們的一些全新列表組件,但我們今天正式宣布它們!不再有 ListView
或 DataSource
、過時的列、被忽略的錯誤或過多的記憶體消耗 - 透過最新的 React Native 2017 年 3 月候選版本 (0.43-rc.1
),您可以從新的組件套件中挑選最適合您用例的組件,它們開箱即用,具有出色的效能和功能集
<FlatList>
這是用於簡單、高效能列表的工作馬組件。提供資料陣列和 renderItem
函式,您就可以開始使用了
<FlatList
data={[{title: 'Title Text', key: 'item1'}, ...]}
renderItem={({item}) => <ListItem title={item.title} />}
/>
<SectionList>
如果您想要呈現一組分成邏輯區段的資料,可能包含區段標題 (例如,在字母順序的通訊錄中),並且可能具有異質資料和呈現方式 (例如,包含一些按鈕、後接撰寫器、然後是照片網格、然後是朋友網格,最後是故事列表的個人資料檢視),這是最佳選擇。
<SectionList
renderItem={({item}) => <ListItem title={item.title} />}
renderSectionHeader={({section}) => <H1 title={section.key} />}
sections={[ // homogeneous rendering between sections
{data: [...], key: ...},
{data: [...], key: ...},
{data: [...], key: ...},
]}
/>
<SectionList
sections={[ // heterogeneous rendering between sections
{data: [...], key: ..., renderItem: ...},
{data: [...], key: ..., renderItem: ...},
{data: [...], key: ..., renderItem: ...},
]}
/>
<VirtualizedList>
幕後實作具有更彈性的 API。如果您的資料不是純陣列 (例如,不可變列表),則特別方便。
功能
列表在許多情境中使用,因此我們在新組件中加入了完整的功能,以處理大多數開箱即用的用例
- 滾動載入 (
onEndReached
)。 - 下拉重新整理 (
onRefresh
/refreshing
)。 - 可配置的可見性 (VPV) 回呼 (
onViewableItemsChanged
/viewabilityConfig
)。 - 水平模式 (
horizontal
)。 - 智慧型項目和區段分隔符。
- 多欄支援 (
numColumns
) scrollToEnd
、scrollToIndex
和scrollToItem
- 更佳的 Flow 型別。
一些注意事項
-
當內容滾動出渲染視窗時,項目子樹的內部狀態不會保留。請確保您的所有資料都擷取在項目資料或外部儲存區中,例如 Flux、Redux 或 Relay。
-
這些組件基於
PureComponent
,這表示如果props
保持淺層相等,它們將不會重新渲染。請確保您的renderItem
函式直接依賴的所有內容都作為 prop 傳遞,該 prop 在更新後不是===
,否則您的 UI 可能不會在變更時更新。這包括data
prop 和父組件狀態。例如<FlatList
data={this.state.data}
renderItem={({item}) => (
<MyItem
item={item}
onPress={() =>
this.setState(oldState => ({
selected: {
// New instance breaks `===`
...oldState.selected, // copy old data
[item.key]: !oldState.selected[item.key], // toggle
},
}))
}
selected={
!!this.state.selected[item.key] // renderItem depends on state
}
/>
)}
selected={
// Can be any prop that doesn't collide with existing props
this.state.selected // A change to selected should re-render FlatList
}
/> -
為了限制記憶體並實現流暢滾動,內容會異步地在螢幕外渲染。這表示滾動速度可能快於填充率,並且可能會短暫看到空白內容。這是一種權衡,可以調整以滿足每個應用程式的需求,我們正在幕後努力改進它。
-
預設情況下,這些新列表會在每個項目上尋找
key
prop,並將其用於 React 金鑰。或者,您可以提供自訂的keyExtractor
prop。
效能
除了簡化 API 之外,新的列表組件還具有顯著的效能增強功能,主要功能是幾乎恆定的記憶體使用量,適用於任何數量的列。這是透過「虛擬化」渲染視窗外部的元素來完成的,方法是將它們從組件層次結構中完全卸載,並從 react 組件回收 JS 記憶體,以及從陰影樹和 UI 檢視回收原生記憶體。這有一個缺點,即內部組件狀態將不會保留,因此請確保您在組件本身外部追蹤任何重要狀態,例如在 Relay 或 Redux 或 Flux 儲存區中。
限制渲染視窗也減少了 React 和原生平台需要完成的工作量,例如來自檢視遍歷。即使您要渲染一百萬個元素的最後一個,使用這些新列表也不需要迭代所有這些元素才能渲染。您甚至可以使用 scrollToIndex
跳到中間,而無需過度渲染。
我們還對排程進行了一些改進,這應有助於應用程式的響應能力。渲染視窗邊緣的項目會不頻繁地渲染,並在任何活動手勢或動畫或其他互動完成後以較低的優先級渲染。
進階用法
與 ListView
不同,渲染視窗中的所有項目會在任何 prop 變更時重新渲染。通常這沒問題,因為視窗化將項目數量減少到恆定數量,但如果您的項目屬於複雜類型,您應確保遵循 React 效能最佳實務,並在您的組件中使用 React.PureComponent
和/或 shouldComponentUpdate
以限制遞迴子樹的重新渲染。
如果您可以在不渲染列的情況下計算列的高度,則可以透過提供 getItemLayout
prop 來改善使用者體驗。這使得使用例如 scrollToIndex
滾動到特定項目時更加流暢,並且將改善滾動指示器 UI,因為可以在不渲染內容的情況下確定內容的高度。
如果您有替代資料類型,例如不可變列表,<VirtualizedList>
是最佳選擇。它採用 getItem
prop,可讓您傳回任何給定索引的項目資料,並具有較寬鬆的 flow 型別。
如果您有不尋常的用例,還可以調整許多參數。例如,您可以使用 windowSize
來權衡記憶體使用量與使用者體驗、maxToRenderPerBatch
來調整填充率與響應能力、onEndReachedThreshold
來控制滾動載入何時發生等等。
未來工作
- 遷移現有表面 (最終棄用
ListView
)。 - 當我們看到/聽到需求時,會提供更多功能 (請告訴我們!)。
- 固定區段標題支援。
- 更多效能最佳化。
- 支援具有狀態的功能項目組件。