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。如果您的数据不是普通数组(例如,不可变列表),则特别方便。
功能
列表在许多上下文中使用,因此我们在新组件中 packed 了完整的功能,以开箱即用地处理大多数用例
- 滚动加载 (
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
不同,渲染窗口中的所有项目在任何 props 更改时都会重新渲染。通常这很好,因为窗口化将项目数量减少到恒定数量,但如果您的项目在复杂方面,您应该确保遵循 React 性能最佳实践,并在您的组件中使用 React.PureComponent
和/或 shouldComponentUpdate
,以限制递归子树的重新渲染。
如果您可以在不渲染行的情况下计算行的高度,则可以通过提供 getItemLayout
prop 来改善用户体验。这使得使用例如 scrollToIndex
滚动到特定项目更加顺畅,并且将改善滚动指示器 UI,因为可以在不渲染内容的情况下确定内容的高度。
如果您有替代数据类型(如不可变列表),则 <VirtualizedList>
是最佳选择。它采用 getItem
prop,使您可以返回任何给定索引的项目数据,并具有更宽松的 flow 类型。
如果您有不寻常的用例,还可以调整许多参数。例如,您可以使用 windowSize
来权衡内存使用量与用户体验、使用 maxToRenderPerBatch
来调整填充率与响应能力、使用 onEndReachedThreshold
来控制滚动加载何时发生等等。
未来工作
- 现有表面的迁移(最终弃用
ListView
)。 - 当我们看到/听到需求时,会添加更多功能(请告诉我们!)。
- 粘性节标题支持。
- 更多性能优化。
- 支持具有状态的功能项目组件。