React Native(简称RN)列表是基于ScrollView实现的,也就是能够滚动的,然而RN并无直接使用IOS或Android的原生列表组件,这是由于RN真正调用native代码的过程是异步的,二Native的渲染要求必须同步渲染的。node
在早期版本中,对于列表状况RN采用的是ListView组件,和Android同样,早期的ListView组件性能是很是的差的,在后来的版本中,RN提供了系列用于提升列表组件性能的组件:FlatList和SectionList。FlatList和SectionList都是基于VirtualizedList实现的。react
读者能够在项目的“node_modules/react-native/Libraries/Lists/XXX”文件夹下找到相关的源码。通常来讲,FlatList和SectionList已经可以知足常见的开发需求,仅当想得到比FlatList 更高的灵活性(好比说在使用 immutable data 而不是普通数组)的时候,才会应该考虑使用VirtualizedList。react-native
VirtualizedList经过维护一个有限的渲染窗口(其中包含可见的元素),并将渲染窗口以外的元素所有用合适的定长空白空间代替的方式,极大的改善了内存消耗以及在有大量数据状况下的使用性能(相似于Android的ListView的界面复用机制)。数组
当一个元素离可视区太远时,它的渲染的优先级较低,不然就得到一个较高的优先级,VirtualizedList经过这种机制来提升列表的渲染性能。在使用VirtualizedList赢注意如下几点:bash
##属性 因为VirtualizedList是FlatList和SectionList的父组件,因此VirtualizedList提供的属性,FlatList和SectionList都可以找到。异步
VirtualizedList执行的流程以下:函数
##循环绘制 循环绘制的加载方法为_scheduleCellsToRenderUpdate()。源码分析
componentDidUpdate() {
this._scheduleCellsToRenderUpdate();
}
复制代码
在每次刷新完成后会调用_scheduleCellsToRenderUpdate方法,该方法最终会调用_updateCellsToRender方法。布局
_updateCellsToRender = () => {
const {data, getItemCount, onEndReachedThreshold} = this.props;
const isVirtualizationDisabled = this._isVirtualizationDisabled();
this._updateViewableItems(data);
if (!data) {
return;
}
this.setState(state => {
let newState;
if (!isVirtualizationDisabled) {
// If we run this with bogus data, we'll force-render window {first: 0, last: 0}, // and wipe out the initialNumToRender rendered elements. // So let's wait until the scroll view metrics have been set up. And until then,
// we will trust the initialNumToRender suggestion
if (this._scrollMetrics.visibleLength) {
// If we have a non-zero initialScrollIndex and run this before we've scrolled, // we'll wipe out the initialNumToRender rendered elements starting at initialScrollIndex.
// So let's wait until we've scrolled the view to the right place. And until then,
// we will trust the initialScrollIndex suggestion.
if (!this.props.initialScrollIndex || this._scrollMetrics.offset) {
newState = computeWindowedRenderLimits(
this.props,
state,
this._getFrameMetricsApprox,
this._scrollMetrics,
);
}
}
} else {
const {contentLength, offset, visibleLength} = this._scrollMetrics;
const distanceFromEnd = contentLength - visibleLength - offset;
const renderAhead =
distanceFromEnd < onEndReachedThreshold * visibleLength
? this.props.maxToRenderPerBatch
: 0;
newState = {
first: 0,
last: Math.min(state.last + renderAhead, getItemCount(data) - 1),
};
}
return newState;
});
};
复制代码
在_updateCellsToRender中会调用setState方法更新状态。因此在每次绘制完成(状态更新完成)后,都会接着调用更新方法,因此造成了循环绘制的效果。理论上这种结构会形成无限循环,可是VirtualizedList是继承自PureComponent,因此当检测到状态未改变的时候就会终止更新。性能
在上述_updateCellsToRender方法中,调用了computeWindowedRenderLimits生成最新的first、last,该方法属于VirtualizeUtils类。它是根据优先级动态计算first和last,距离屏幕显示组件的数据越近,优先级越高。