mirror of
https://github.com/status-im/react-native.git
synced 2025-02-10 08:26:23 +00:00
Support virtualization and onViewableItemsChanged for nested, same-orientation VirtualizedLists
Reviewed By: sahrens Differential Revision: D6330846 fbshipit-source-id: c555f4d449b75753befbd376dbf4e6fb4812fa75
This commit is contained in:
parent
d2dc451407
commit
2668dc8e1b
@ -114,6 +114,15 @@ function computeWindowedRenderLimits(
|
|||||||
);
|
);
|
||||||
const overscanEnd = Math.max(0, visibleEnd + leadFactor * overscanLength);
|
const overscanEnd = Math.max(0, visibleEnd + leadFactor * overscanLength);
|
||||||
|
|
||||||
|
const lastItemOffset = getFrameMetricsApprox(itemCount - 1).offset;
|
||||||
|
if (lastItemOffset < overscanBegin) {
|
||||||
|
// Entire list is before our overscan window
|
||||||
|
return {
|
||||||
|
first: Math.max(0, itemCount - 1 - maxToRenderPerBatch),
|
||||||
|
last: itemCount - 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Find the indices that correspond to the items at the render boundaries we're targetting.
|
// Find the indices that correspond to the items at the render boundaries we're targetting.
|
||||||
let [overscanFirst, first, last, overscanLast] = elementsThatOverlapOffsets(
|
let [overscanFirst, first, last, overscanLast] = elementsThatOverlapOffsets(
|
||||||
[overscanBegin, visibleBegin, visibleEnd, overscanEnd],
|
[overscanBegin, visibleBegin, visibleEnd, overscanEnd],
|
||||||
|
@ -20,6 +20,7 @@ const ReactNative = require('ReactNative');
|
|||||||
const RefreshControl = require('RefreshControl');
|
const RefreshControl = require('RefreshControl');
|
||||||
const ScrollView = require('ScrollView');
|
const ScrollView = require('ScrollView');
|
||||||
const StyleSheet = require('StyleSheet');
|
const StyleSheet = require('StyleSheet');
|
||||||
|
const UIManager = require('UIManager');
|
||||||
const View = require('View');
|
const View = require('View');
|
||||||
const ViewabilityHelper = require('ViewabilityHelper');
|
const ViewabilityHelper = require('ViewabilityHelper');
|
||||||
|
|
||||||
@ -129,6 +130,12 @@ type OptionalProps = {
|
|||||||
* a rendered element.
|
* a rendered element.
|
||||||
*/
|
*/
|
||||||
ListHeaderComponent?: ?(React.ComponentType<any> | React.Element<any>),
|
ListHeaderComponent?: ?(React.ComponentType<any> | React.Element<any>),
|
||||||
|
/**
|
||||||
|
* A unique identifier for this list. If there are multiple VirtualizedLists at the same level of
|
||||||
|
* nesting within another VirtualizedList, this key is necessary for virtualization to
|
||||||
|
* work properly.
|
||||||
|
*/
|
||||||
|
listKey?: string,
|
||||||
/**
|
/**
|
||||||
* The maximum number of items to render in each incremental render batch. The more rendered at
|
* The maximum number of items to render in each incremental render batch. The more rendered at
|
||||||
* once, the better the fill rate, but responsiveness my suffer because rendering content may
|
* once, the better the fill rate, but responsiveness my suffer because rendering content may
|
||||||
@ -206,6 +213,19 @@ export type Props = RequiredProps & OptionalProps;
|
|||||||
|
|
||||||
let _usedIndexForKey = false;
|
let _usedIndexForKey = false;
|
||||||
|
|
||||||
|
type Frame = {
|
||||||
|
offset: number,
|
||||||
|
length: number,
|
||||||
|
index: number,
|
||||||
|
inLayout: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
type ChildListState = {
|
||||||
|
first: number,
|
||||||
|
last: number,
|
||||||
|
frames: {[key: number]: Frame},
|
||||||
|
};
|
||||||
|
|
||||||
type State = {first: number, last: number};
|
type State = {first: number, last: number};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -412,26 +432,92 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
|
virtualizedListCellRenderer: PropTypes.shape({
|
||||||
|
cellKey: PropTypes.string,
|
||||||
|
}),
|
||||||
virtualizedList: PropTypes.shape({
|
virtualizedList: PropTypes.shape({
|
||||||
|
getScrollMetrics: PropTypes.func,
|
||||||
horizontal: PropTypes.bool,
|
horizontal: PropTypes.bool,
|
||||||
|
getOutermostParentListRef: PropTypes.func,
|
||||||
|
registerAsNestedChild: PropTypes.func,
|
||||||
|
unregisterAsNestedChild: PropTypes.func,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
static childContextTypes = {
|
static childContextTypes = {
|
||||||
virtualizedList: PropTypes.shape({
|
virtualizedList: PropTypes.shape({
|
||||||
|
getScrollMetrics: PropTypes.func,
|
||||||
horizontal: PropTypes.bool,
|
horizontal: PropTypes.bool,
|
||||||
|
getOutermostParentListRef: PropTypes.func,
|
||||||
|
registerAsNestedChild: PropTypes.func,
|
||||||
|
unregisterAsNestedChild: PropTypes.func,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
getChildContext() {
|
getChildContext() {
|
||||||
return {
|
return {
|
||||||
virtualizedList: {
|
virtualizedList: {
|
||||||
|
getScrollMetrics: this._getScrollMetrics,
|
||||||
horizontal: this.props.horizontal,
|
horizontal: this.props.horizontal,
|
||||||
// TODO: support nested virtualization and onViewableItemsChanged
|
getOutermostParentListRef: this._getOutermostParentListRef,
|
||||||
|
registerAsNestedChild: this._registerAsNestedChild,
|
||||||
|
unregisterAsNestedChild: this._unregisterAsNestedChild,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_getScrollMetrics = () => {
|
||||||
|
return this._scrollMetrics;
|
||||||
|
};
|
||||||
|
|
||||||
|
hasMore(): boolean {
|
||||||
|
return this._hasMore;
|
||||||
|
}
|
||||||
|
|
||||||
|
_getOutermostParentListRef = () => {
|
||||||
|
if (this._isNestedWithSameOrientation()) {
|
||||||
|
return this.context.virtualizedList.getOutermostParentListRef();
|
||||||
|
} else {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_registerAsNestedChild = (childList: {
|
||||||
|
cellKey: string,
|
||||||
|
key: string,
|
||||||
|
ref: VirtualizedList,
|
||||||
|
}): ?ChildListState => {
|
||||||
|
// Register the mapping between this child key and the cellKey for its cell
|
||||||
|
const childListsInCell =
|
||||||
|
this._cellKeysToChildListKeys.get(childList.cellKey) || new Set();
|
||||||
|
childListsInCell.add(childList.key);
|
||||||
|
this._cellKeysToChildListKeys.set(childList.cellKey, childListsInCell);
|
||||||
|
|
||||||
|
const existingChildData = this._nestedChildLists.get(childList.key);
|
||||||
|
invariant(
|
||||||
|
!(existingChildData && existingChildData.ref !== null),
|
||||||
|
'A VirtualizedList contains a cell which itself contains ' +
|
||||||
|
'more than one VirtualizedList of the same orientation as the parent ' +
|
||||||
|
'list. You must pass a unique listKey prop to each sibling list.',
|
||||||
|
);
|
||||||
|
this._nestedChildLists.set(childList.key, {
|
||||||
|
ref: childList.ref,
|
||||||
|
state: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
return existingChildData && existingChildData.state;
|
||||||
|
};
|
||||||
|
|
||||||
|
_unregisterAsNestedChild = (childList: {
|
||||||
|
key: string,
|
||||||
|
state: ChildListState,
|
||||||
|
}): void => {
|
||||||
|
this._nestedChildLists.set(childList.key, {
|
||||||
|
ref: null,
|
||||||
|
state: childList.state,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
state: State;
|
state: State;
|
||||||
|
|
||||||
constructor(props: Props, context: Object) {
|
constructor(props: Props, context: Object) {
|
||||||
@ -441,11 +527,6 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
|||||||
'Components based on VirtualizedList must be wrapped with Animated.createAnimatedComponent ' +
|
'Components based on VirtualizedList must be wrapped with Animated.createAnimatedComponent ' +
|
||||||
'to support native onScroll events with useNativeDriver',
|
'to support native onScroll events with useNativeDriver',
|
||||||
);
|
);
|
||||||
invariant(
|
|
||||||
!(this._isNestedWithSameOrientation() && props.onViewableItemsChanged),
|
|
||||||
'Nesting lists that scroll in the same direction does not support onViewableItemsChanged' +
|
|
||||||
'on the inner list.',
|
|
||||||
);
|
|
||||||
|
|
||||||
this._fillRateHelper = new FillRateHelper(this._getFrameMetrics);
|
this._fillRateHelper = new FillRateHelper(this._getFrameMetrics);
|
||||||
this._updateCellsToRenderBatcher = new Batchinator(
|
this._updateCellsToRenderBatcher = new Batchinator(
|
||||||
@ -467,7 +548,7 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.state = {
|
let initialState = {
|
||||||
first: this.props.initialScrollIndex || 0,
|
first: this.props.initialScrollIndex || 0,
|
||||||
last:
|
last:
|
||||||
Math.min(
|
Math.min(
|
||||||
@ -475,7 +556,26 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
|||||||
(this.props.initialScrollIndex || 0) + this.props.initialNumToRender,
|
(this.props.initialScrollIndex || 0) + this.props.initialNumToRender,
|
||||||
) - 1,
|
) - 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (this._isNestedWithSameOrientation()) {
|
||||||
|
const storedState = this.context.virtualizedList.registerAsNestedChild({
|
||||||
|
cellKey: this.context.virtualizedListCellRenderer.cellKey,
|
||||||
|
key:
|
||||||
|
this.props.listKey ||
|
||||||
|
this.context.virtualizedListCellRenderer.cellKey,
|
||||||
|
ref: this,
|
||||||
|
});
|
||||||
|
if (storedState) {
|
||||||
|
initialState = storedState;
|
||||||
|
this.state = storedState;
|
||||||
|
this._frames = storedState.frames;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.state = initialState;
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillMount() {}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
if (this.props.initialScrollIndex) {
|
if (this.props.initialScrollIndex) {
|
||||||
@ -491,8 +591,20 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
|
if (this._isNestedWithSameOrientation()) {
|
||||||
|
this.context.virtualizedList.unregisterAsNestedChild({
|
||||||
|
key:
|
||||||
|
this.props.listKey ||
|
||||||
|
this.context.virtualizedListCellRenderer.cellKey,
|
||||||
|
state: {
|
||||||
|
first: this.state.first,
|
||||||
|
last: this.state.last,
|
||||||
|
frames: this._frames,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
this._updateViewableItems(null);
|
this._updateViewableItems(null);
|
||||||
this._updateCellsToRenderBatcher.dispose();
|
this._updateCellsToRenderBatcher.dispose({abort: true});
|
||||||
this._viewabilityTuples.forEach(tuple => {
|
this._viewabilityTuples.forEach(tuple => {
|
||||||
tuple.viewabilityHelper.dispose();
|
tuple.viewabilityHelper.dispose();
|
||||||
});
|
});
|
||||||
@ -549,6 +661,7 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
|||||||
for (let ii = first; ii <= last; ii++) {
|
for (let ii = first; ii <= last; ii++) {
|
||||||
const item = getItem(data, ii);
|
const item = getItem(data, ii);
|
||||||
const key = keyExtractor(item, ii);
|
const key = keyExtractor(item, ii);
|
||||||
|
this._indicesToKeys.set(ii, key);
|
||||||
if (stickyIndicesFromProps.has(ii + stickyOffset)) {
|
if (stickyIndicesFromProps.has(ii + stickyOffset)) {
|
||||||
stickyHeaderIndices.push(cells.length);
|
stickyHeaderIndices.push(cells.length);
|
||||||
}
|
}
|
||||||
@ -585,9 +698,7 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_isVirtualizationDisabled(): boolean {
|
_isVirtualizationDisabled(): boolean {
|
||||||
return (
|
return this.props.disableVirtualization;
|
||||||
this.props.disableVirtualization || this._isNestedWithSameOrientation()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_isNestedWithSameOrientation(): boolean {
|
_isNestedWithSameOrientation(): boolean {
|
||||||
@ -606,7 +717,6 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
|||||||
'Consider using `numColumns` with `FlatList` instead.',
|
'Consider using `numColumns` with `FlatList` instead.',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
ListEmptyComponent,
|
ListEmptyComponent,
|
||||||
ListFooterComponent,
|
ListFooterComponent,
|
||||||
@ -779,6 +889,10 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
|||||||
if (inversionStyle) {
|
if (inversionStyle) {
|
||||||
scrollProps.style = [inversionStyle, this.props.style];
|
scrollProps.style = [inversionStyle, this.props.style];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._hasMore =
|
||||||
|
this.state.last < this.props.getItemCount(this.props.data) - 1;
|
||||||
|
|
||||||
const ret = React.cloneElement(
|
const ret = React.cloneElement(
|
||||||
(this.props.renderScrollComponent || this._defaultRenderScrollComponent)(
|
(this.props.renderScrollComponent || this._defaultRenderScrollComponent)(
|
||||||
scrollProps,
|
scrollProps,
|
||||||
@ -805,15 +919,25 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_averageCellLength = 0;
|
_averageCellLength = 0;
|
||||||
|
// Maps a cell key to the set of keys for all outermost child lists within that cell
|
||||||
|
_cellKeysToChildListKeys: Map<string, Set<string>> = new Map();
|
||||||
_cellRefs = {};
|
_cellRefs = {};
|
||||||
_hasDataChangedSinceEndReached = true;
|
|
||||||
_hasWarned = {};
|
|
||||||
_highestMeasuredFrameIndex = 0;
|
|
||||||
_headerLength = 0;
|
|
||||||
_initialScrollIndexTimeout = 0;
|
|
||||||
_fillRateHelper: FillRateHelper;
|
_fillRateHelper: FillRateHelper;
|
||||||
_frames = {};
|
_frames = {};
|
||||||
_footerLength = 0;
|
_footerLength = 0;
|
||||||
|
_hasDataChangedSinceEndReached = true;
|
||||||
|
_hasMore = false;
|
||||||
|
_hasWarned = {};
|
||||||
|
_highestMeasuredFrameIndex = 0;
|
||||||
|
_headerLength = 0;
|
||||||
|
_indicesToKeys: Map<number, string> = new Map();
|
||||||
|
_initialScrollIndexTimeout = 0;
|
||||||
|
_nestedChildLists: Map<
|
||||||
|
string,
|
||||||
|
{ref: ?VirtualizedList, state: ?ChildListState},
|
||||||
|
> = new Map();
|
||||||
|
_offsetFromParentVirtualizedList: number = 0;
|
||||||
|
_prevParentOffset: number = 0;
|
||||||
_scrollMetrics = {
|
_scrollMetrics = {
|
||||||
contentLength: 0,
|
contentLength: 0,
|
||||||
dOffset: 0,
|
dOffset: 0,
|
||||||
@ -910,10 +1034,41 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_measureLayoutRelativeToContainingList(): void {
|
||||||
|
UIManager.measureLayout(
|
||||||
|
ReactNative.findNodeHandle(this),
|
||||||
|
ReactNative.findNodeHandle(
|
||||||
|
this.context.virtualizedList.getOutermostParentListRef(),
|
||||||
|
),
|
||||||
|
error => {
|
||||||
|
console.warn(
|
||||||
|
"VirtualizedList: Encountered an error while measuring a list's" +
|
||||||
|
' offset from its containing VirtualizedList.',
|
||||||
|
);
|
||||||
|
},
|
||||||
|
(x, y, width, height) => {
|
||||||
|
this._offsetFromParentVirtualizedList = this._selectOffset({x, y});
|
||||||
|
this._scrollMetrics.contentLength = this._selectLength({width, height});
|
||||||
|
|
||||||
|
const scrollMetrics = this._convertParentScrollMetrics(
|
||||||
|
this.context.virtualizedList.getScrollMetrics(),
|
||||||
|
);
|
||||||
|
this._scrollMetrics.visibleLength = scrollMetrics.visibleLength;
|
||||||
|
this._scrollMetrics.offset = scrollMetrics.offset;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
_onLayout = (e: Object) => {
|
_onLayout = (e: Object) => {
|
||||||
|
if (this._isNestedWithSameOrientation()) {
|
||||||
|
// Need to adjust our scroll metrics to be relative to our containing
|
||||||
|
// VirtualizedList before we can make claims about list item viewability
|
||||||
|
this._measureLayoutRelativeToContainingList();
|
||||||
|
} else {
|
||||||
this._scrollMetrics.visibleLength = this._selectLength(
|
this._scrollMetrics.visibleLength = this._selectLength(
|
||||||
e.nativeEvent.layout,
|
e.nativeEvent.layout,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
this.props.onLayout && this.props.onLayout(e);
|
this.props.onLayout && this.props.onLayout(e);
|
||||||
this._scheduleCellsToRenderUpdate();
|
this._scheduleCellsToRenderUpdate();
|
||||||
this._maybeCallOnEndReached();
|
this._maybeCallOnEndReached();
|
||||||
@ -1033,17 +1188,63 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
|||||||
this._maybeCallOnEndReached();
|
this._maybeCallOnEndReached();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Translates metrics from a scroll event in a parent VirtualizedList into
|
||||||
|
* coordinates relative to the child list.
|
||||||
|
*/
|
||||||
|
_convertParentScrollMetrics = (metrics: {
|
||||||
|
visibleLength: number,
|
||||||
|
offset: number,
|
||||||
|
}) => {
|
||||||
|
// Offset of the top of the nested list relative to the top of its parent's viewport
|
||||||
|
const offset = metrics.offset - this._offsetFromParentVirtualizedList;
|
||||||
|
// Child's visible length is the same as its parent's
|
||||||
|
const visibleLength = metrics.visibleLength;
|
||||||
|
const dOffset = offset - this._scrollMetrics.offset;
|
||||||
|
const contentLength = this._scrollMetrics.contentLength;
|
||||||
|
|
||||||
|
return {
|
||||||
|
visibleLength,
|
||||||
|
contentLength,
|
||||||
|
offset,
|
||||||
|
dOffset,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
_onScroll = (e: Object) => {
|
_onScroll = (e: Object) => {
|
||||||
|
this._nestedChildLists.forEach(childList => {
|
||||||
|
childList.ref && childList.ref._onScroll(e);
|
||||||
|
});
|
||||||
if (this.props.onScroll) {
|
if (this.props.onScroll) {
|
||||||
this.props.onScroll(e);
|
this.props.onScroll(e);
|
||||||
}
|
}
|
||||||
const timestamp = e.timeStamp;
|
const timestamp = e.timeStamp;
|
||||||
const visibleLength = this._selectLength(e.nativeEvent.layoutMeasurement);
|
let visibleLength = this._selectLength(e.nativeEvent.layoutMeasurement);
|
||||||
const contentLength = this._selectLength(e.nativeEvent.contentSize);
|
let contentLength = this._selectLength(e.nativeEvent.contentSize);
|
||||||
const offset = this._selectOffset(e.nativeEvent.contentOffset);
|
let offset = this._selectOffset(e.nativeEvent.contentOffset);
|
||||||
|
let dOffset = offset - this._scrollMetrics.offset;
|
||||||
|
|
||||||
|
if (this._isNestedWithSameOrientation()) {
|
||||||
|
if (this._scrollMetrics.contentLength === 0) {
|
||||||
|
// Ignore scroll events until onLayout has been called and we
|
||||||
|
// know our offset from our offset from our parent
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
({
|
||||||
|
visibleLength,
|
||||||
|
contentLength,
|
||||||
|
offset,
|
||||||
|
dOffset,
|
||||||
|
} = this._convertParentScrollMetrics({
|
||||||
|
visibleLength,
|
||||||
|
offset,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
const dt = this._scrollMetrics.timestamp
|
const dt = this._scrollMetrics.timestamp
|
||||||
? Math.max(1, timestamp - this._scrollMetrics.timestamp)
|
? Math.max(1, timestamp - this._scrollMetrics.timestamp)
|
||||||
: 1;
|
: 1;
|
||||||
|
const velocity = dOffset / dt;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
dt > 500 &&
|
dt > 500 &&
|
||||||
this._scrollMetrics.dt > 500 &&
|
this._scrollMetrics.dt > 500 &&
|
||||||
@ -1058,8 +1259,6 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
|||||||
);
|
);
|
||||||
this._hasWarned.perf = true;
|
this._hasWarned.perf = true;
|
||||||
}
|
}
|
||||||
const dOffset = offset - this._scrollMetrics.offset;
|
|
||||||
const velocity = dOffset / dt;
|
|
||||||
this._scrollMetrics = {
|
this._scrollMetrics = {
|
||||||
contentLength,
|
contentLength,
|
||||||
dt,
|
dt,
|
||||||
@ -1175,6 +1374,36 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
|||||||
last: Math.min(state.last + renderAhead, getItemCount(data) - 1),
|
last: Math.min(state.last + renderAhead, getItemCount(data) - 1),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (newState && this._nestedChildLists.size > 0) {
|
||||||
|
const newFirst = newState.first;
|
||||||
|
const newLast = newState.last;
|
||||||
|
// If some cell in the new state has a child list in it, we should only render
|
||||||
|
// up through that item, so that we give that list a chance to render.
|
||||||
|
// Otherwise there's churn from multiple child lists mounting and un-mounting
|
||||||
|
// their items.
|
||||||
|
for (let ii = newFirst; ii <= newLast; ii++) {
|
||||||
|
const cellKeyForIndex = this._indicesToKeys.get(ii);
|
||||||
|
const childListKeys =
|
||||||
|
cellKeyForIndex &&
|
||||||
|
this._cellKeysToChildListKeys.get(cellKeyForIndex);
|
||||||
|
if (!childListKeys) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let someChildHasMore = false;
|
||||||
|
// For each cell, need to check whether any child list in it has more elements to render
|
||||||
|
for (let childKey of childListKeys) {
|
||||||
|
const childList = this._nestedChildLists.get(childKey);
|
||||||
|
if (childList && childList.ref && childList.ref.hasMore()) {
|
||||||
|
someChildHasMore = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (someChildHasMore) {
|
||||||
|
newState.last = ii;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return newState;
|
return newState;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -1292,6 +1521,20 @@ class CellRenderer extends React.Component<
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static childContextTypes = {
|
||||||
|
virtualizedListCellRenderer: PropTypes.shape({
|
||||||
|
cellKey: PropTypes.string,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
getChildContext() {
|
||||||
|
return {
|
||||||
|
virtualizedListCellRenderer: {
|
||||||
|
cellKey: this.props.cellKey,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: consider factoring separator stuff out of VirtualizedList into FlatList since it's not
|
// TODO: consider factoring separator stuff out of VirtualizedList into FlatList since it's not
|
||||||
// reused by SectionList and we can keep VirtualizedList simpler.
|
// reused by SectionList and we can keep VirtualizedList simpler.
|
||||||
_separators = {
|
_separators = {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user