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,距離屏幕顯示組件的數據越近,優先級越高。