ReactNative列表是基于ScrollView的,并没有直接使用IOS或Android的原生列表组件。因为RN真正调用native代码是异步的,并不能保证同步,而在native环境中,所有即将在视窗中呈现的元素都必须同步渲染,超过一定的时间(ios为16ms)就会出现掉帧,所以RN采用ScrollView作为列表组件的基础。
ReactNative刚开始提供的是ListView组件,在数据量大的情况下,性能特别差。目前提供的列表组件是FlatList和SectionList,性能问题得到了很好的解决,它们都是基于VirtualizedList。
下文引用的源码基于ReactNative 0.51,node_modules/react-native/Libraries/Lists/目录下。
VirtualizedList原理
- 每次新增绘制item的最大数量为10,循环绘制(以10为单位累加绘制);
- 首先绘制显示在屏幕中的items,再根据优先级循环绘制屏幕上显示items相近的数据,直至绘制完成;
- 每次绘制过程中,所有不需要绘制的元素用空View代替;
源码分析
render
方法(空间原因有删减):
const {
ListEmptyComponent,//数据为空显示样式
ListFooterComponent,//footer
ListHeaderComponent,//header
} = this.props;
const {data, horizontal} = this.props;
const isVirtualizationDisabled = this._isVirtualizationDisabled();
//确定反转样式
const inversionStyle = this.props.inverted
? this.props.horizontal ? styles.horizontallyInverted : styles.verticallyInverted
: null;
const cells = [];//list显示view集合
//section集合(即SectionList中的分组)
const stickyIndicesFromProps = new Set(this.props.stickyHeaderIndices);
const stickyHeaderIndices = [];
//处理header
if (ListHeaderComponent) {
if (stickyIndicesFromProps.has(0)) {
stickyHeaderIndices.push(0);
}
const element = React.isValidElement(ListHeaderComponent)
? (ListHeaderComponent)
: (<ListHeaderComponent/>);
cells.push(
<View
key="$header"
onLayout={this._onLayoutHeader}
style={inversionStyle}>
{element}
</View>,
);
}