VirtualizedList
React 17.0.2
React-native 0.67.3
VirtualizedList
VirtualizedList
<VirtualizedList
data={[{key: 'i1'}, {key: 'i2'}, {key: 'i3'}]}
renderItem={({item}) => <item value={item.key} />}
getItem={(data, index) => data[index]}
getItemCount={data => data.length}
/>
maxToRenderPerBatch,每次渲染的个数
初始化
- FillRateHelper 初始化
- Batchinator初始化
- initialState的first和last赋值,first为initialScrollIndex(默认0),last为first+initialNumToRender
windowSize
默认21。1相当于一个可视窗口,数字大时看到白屏的几率少,数字小时内存占用少
initialNumToRender,首次渲染个数,默认10个。指定一开始渲染的元素数量,最好刚刚够填满一个屏幕,这样保证了用最短的时间给用户呈现可见的内容。注意这第一批次渲染的元素不会在滑动过程中被卸载,这样是为了保证用户执行返回顶部的操作时,不需要重新渲染首批元素。
先介绍_pushCells作用,这里会把first到last(参数)的CellRenderer push进去
render
- 调用_pushCells,first为0,last为initialNumToRender(默认10)
- 接着再调用_pushCells,first为firstAfterInitial(Math.max(lastInitialIndex + 1, first)),其中lastInitialIndex为initialNumToRender,last则为全局变量last(初始为initialNumToRender,后为state.last+maxToRenderPerBatch)
- 假设isVirtualizationDisabled没有禁用,并且last小于item个数,cells会在尾部push一个view
- 如果last小于item个数,_hasMore赋值为true
- 最后调用innerRet,返回一个ScrollView,体现为_scrollRef
_maybeCallOnEndReached,如果last为数据源最后一个,调用onEndReached
_maybeCallOnEndReached的Caller
- _onLayout
- _onContentSizeChange
- _onScroll
_scheduleCellsToRenderUpdate
- 这里会进行高优先级判断,如果接近最后一项则标记为高优先级
- 若高优先级,则直接调用_updateCellsToRender渲染,若非高优先级则this._updateCellsToRenderBatcher.schedule()进行调度渲染
_scheduleCellsToRenderUpdate的Caller
- componentDidUpdate
- _onCellLayout
- _onLayout
- _onContentSizeChange
- _onScroll
_onScroll
- _updateViewableItems,这里会调用ViewabilityHelper的onUpdate方法,这里会找出哪些item是可见的,并且调用onViewableItemsChanged,通知可见项目发生了改变
- _maybeCallOnEndReached
- _scheduleCellsToRenderUpdate
- 如果是高优先级任务,先调用_updateCellsToRenderBatcher的dispose方法,然后调用_updateCellsToRender
- 如果是低优先级任务,调用_updateCellsToRenderBatcher的schedule,这里是异步执行callback,callback的内容是调用_updateCellsToRender方法
_updateCellsToRender
- _updateViewableItems
- 调用setState进行更新
CellRenderer
CellRenderer
- 一个普通View/CellRendererComponent(外部传入)作为容器
- 里面的element由外部传入,通过React.createElement生成
- 最终通过VirtualizedListCellContextProvider 返回
FlatList
官方示例
class MyListItem extends React.PureComponent {
_onPress = () => {
this.props.onPressItem(this.props.id);
};
render() {
const textColor = this.props.selected ? "red" : "black";
return (
<TouchableOpacity onPress={this._onPress}>
<View>
<Text style={{ color: textColor }}>
{this.props.title}
</Text>
</View>
</TouchableOpacity>
);
}
}
class MultiSelectList extends React.PureComponent {
state = {selected: (new Map(): Map<string, boolean>)};
_keyExtractor = (item, index) => item.id;
_onPressItem = (id: string) => {
// updater functions are preferred for transactional updates
this.setState((state) => {
// copy the map rather than modifying state.
const selected = new Map(state.selected);
selected.set(id, !selected.get(id)); // toggle
return {selected};
});
};
_renderItem = ({item}) => (
<MyListItem
id={item.id}
onPressItem={this._onPressItem}
selected={!!this.state.selected.get(item.id)}
title={item.title}
/>
);
render() {
return (
<FlatList
data={this.props.data}
extraData={this.state}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
/>
);
}
}
render函数的实现
外层为VirtualizedList
内层调用_renderer函数,返回renderItem
- 若列数不大于1则直接调用renderer函数,renderer函数内返回调用renderItem
- 若列数大于1,则返回一个View,View内遍历item(Array类型),返回Fragment,Fragment内会调用renderer函数
renderer函数内,如果设置了ListItemComponent,则返回ListItemComponent,否则返回renderItem函数调用