mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Remove dependence on VirtualizedList listKey prop
Summary: Following up on the previous diff to remove the only usage of `listKey` for persistent association, we can remove the need for a manual `listKey`, and instead rely on per-instance association via refs. A followup change will remove the existing usages. Changelog: [General][Removed] - Remove VirtualizedList `listKey` prop Reviewed By: p-sun Differential Revision: D39466677 fbshipit-source-id: 6b49f45c987fff9836918ba833fbb16f24414ff8
This commit is contained in:
committed by
Facebook GitHub Bot
parent
c5217f199d
commit
010da67bef
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
import invariant from 'invariant';
|
||||
|
||||
export default class ChildListCollection<TList> {
|
||||
_cellKeyToChildren: Map<string, Set<TList>> = new Map();
|
||||
_childrenToCellKey: Map<TList, string> = new Map();
|
||||
|
||||
add(list: TList, cellKey: string): void {
|
||||
invariant(
|
||||
!this._childrenToCellKey.has(list),
|
||||
'Trying to add already present child list',
|
||||
);
|
||||
|
||||
const cellLists = this._cellKeyToChildren.get(cellKey) ?? new Set();
|
||||
cellLists.add(list);
|
||||
this._cellKeyToChildren.set(cellKey, cellLists);
|
||||
|
||||
this._childrenToCellKey.set(list, cellKey);
|
||||
}
|
||||
|
||||
remove(list: TList): void {
|
||||
const cellKey = this._childrenToCellKey.get(list);
|
||||
invariant(cellKey != null, 'Trying to remove non-present child list');
|
||||
this._childrenToCellKey.delete(list);
|
||||
|
||||
const cellLists = this._cellKeyToChildren.get(cellKey);
|
||||
invariant(cellLists, '_cellKeyToChildren should contain cellKey');
|
||||
cellLists.delete(list);
|
||||
|
||||
if (cellLists.size === 0) {
|
||||
this._cellKeyToChildren.delete(cellKey);
|
||||
}
|
||||
}
|
||||
|
||||
forEach(fn: TList => void): void {
|
||||
for (const listSet of this._cellKeyToChildren.values()) {
|
||||
for (const list of listSet) {
|
||||
fn(list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
forEachInCell(cellKey: string, fn: TList => void): void {
|
||||
const listSet = this._cellKeyToChildren.get(cellKey) ?? [];
|
||||
for (const list of listSet) {
|
||||
fn(list);
|
||||
}
|
||||
}
|
||||
|
||||
anyInCell(cellKey: string, fn: TList => boolean): boolean {
|
||||
const listSet = this._cellKeyToChildren.get(cellKey) ?? [];
|
||||
for (const list of listSet) {
|
||||
if (fn(list)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size(): number {
|
||||
return this._childrenToCellKey.size;
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,6 @@ import type {
|
||||
export type {RenderItemProps, RenderItemType, Separators};
|
||||
|
||||
import {
|
||||
type ListDebugInfo,
|
||||
VirtualizedListCellContextProvider,
|
||||
VirtualizedListContext,
|
||||
VirtualizedListContextProvider,
|
||||
@@ -35,6 +34,7 @@ import {
|
||||
} from './VirtualizeUtils';
|
||||
import * as VirtualizedListInjection from './VirtualizedListInjection';
|
||||
import * as React from 'react';
|
||||
import ChildListCollection from './ChildListCollection';
|
||||
|
||||
const RefreshControl = require('../Components/RefreshControl/RefreshControl');
|
||||
const ScrollView = require('../Components/ScrollView/ScrollView');
|
||||
@@ -294,7 +294,7 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
||||
|
||||
recordInteraction() {
|
||||
this._nestedChildLists.forEach(childList => {
|
||||
childList && childList.recordInteraction();
|
||||
childList.recordInteraction();
|
||||
});
|
||||
this._viewabilityTuples.forEach(t => {
|
||||
t.viewabilityHelper.recordInteraction();
|
||||
@@ -349,19 +349,6 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
||||
return this.context?.cellKey || 'rootList';
|
||||
}
|
||||
|
||||
_getListKey(): string {
|
||||
return this.props.listKey || this._getCellKey();
|
||||
}
|
||||
|
||||
_getDebugInfo(): ListDebugInfo {
|
||||
return {
|
||||
listKey: this._getListKey(),
|
||||
cellKey: this._getCellKey(),
|
||||
horizontal: horizontalOrDefault(this.props.horizontal),
|
||||
parent: this.context?.debugInfo,
|
||||
};
|
||||
}
|
||||
|
||||
// $FlowFixMe[missing-local-annot]
|
||||
_getScrollMetrics = () => {
|
||||
return this._scrollMetrics;
|
||||
@@ -382,41 +369,20 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
||||
|
||||
_registerAsNestedChild = (childList: {
|
||||
cellKey: string,
|
||||
key: string,
|
||||
ref: React.ElementRef<typeof React.Component>,
|
||||
parentDebugInfo: ListDebugInfo,
|
||||
...
|
||||
}): void => {
|
||||
const specificRef = ((childList.ref: any): VirtualizedList);
|
||||
// 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);
|
||||
if (existingChildData) {
|
||||
console.error(
|
||||
'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.\n\n' +
|
||||
describeNestedLists({
|
||||
...childList,
|
||||
ref: specificRef,
|
||||
// We're called from the child's componentDidMount, so it's safe to
|
||||
// read the child's props here (albeit weird).
|
||||
horizontal: !!specificRef.props.horizontal,
|
||||
}),
|
||||
);
|
||||
}
|
||||
this._nestedChildLists.set(childList.key, specificRef);
|
||||
|
||||
const listRef = ((childList.ref: any): VirtualizedList);
|
||||
this._nestedChildLists.add(listRef, childList.cellKey);
|
||||
if (this._hasInteracted) {
|
||||
specificRef.recordInteraction();
|
||||
listRef.recordInteraction();
|
||||
}
|
||||
};
|
||||
|
||||
_unregisterAsNestedChild = (childList: {key: string, ...}): void => {
|
||||
this._nestedChildLists.delete(childList.key);
|
||||
_unregisterAsNestedChild = (childList: {
|
||||
ref: React.ElementRef<typeof React.Component>,
|
||||
}): void => {
|
||||
const listRef = ((childList.ref: any): VirtualizedList);
|
||||
this._nestedChildLists.remove(listRef);
|
||||
};
|
||||
|
||||
state: State;
|
||||
@@ -476,28 +442,15 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
||||
componentDidMount() {
|
||||
if (this._isNestedWithSameOrientation()) {
|
||||
this.context.registerAsNestedChild({
|
||||
cellKey: this._getCellKey(),
|
||||
key: this._getListKey(),
|
||||
ref: this,
|
||||
// NOTE: When the child mounts (here) it's not necessarily safe to read
|
||||
// the parent's props. This is why we explicitly propagate debugInfo
|
||||
// "down" via context and "up" again via this method call on the
|
||||
// parent.
|
||||
parentDebugInfo: this.context.debugInfo,
|
||||
cellKey: this.context.cellKey,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this._isNestedWithSameOrientation()) {
|
||||
this.context.unregisterAsNestedChild({
|
||||
key: this._getListKey(),
|
||||
state: {
|
||||
first: this.state.first,
|
||||
last: this.state.last,
|
||||
frames: this._frames,
|
||||
},
|
||||
});
|
||||
this.context.unregisterAsNestedChild({ref: this});
|
||||
}
|
||||
this._updateViewableItems(null);
|
||||
this._updateCellsToRenderBatcher.dispose({abort: true});
|
||||
@@ -851,7 +804,6 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
||||
getOutermostParentListRef: this._getOutermostParentListRef,
|
||||
registerAsNestedChild: this._registerAsNestedChild,
|
||||
unregisterAsNestedChild: this._unregisterAsNestedChild,
|
||||
debugInfo: this._getDebugInfo(),
|
||||
}}>
|
||||
{React.cloneElement(
|
||||
(
|
||||
@@ -927,8 +879,6 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
_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: {[string]: null | CellRenderer} = {};
|
||||
_fillRateHelper: FillRateHelper;
|
||||
_frames: {
|
||||
@@ -949,7 +899,8 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
||||
_hiPriInProgress: boolean = false; // flag to prevent infinite hiPri cell limit update
|
||||
_highestMeasuredFrameIndex = 0;
|
||||
_indicesToKeys: Map<number, string> = new Map();
|
||||
_nestedChildLists: Map<string, VirtualizedList> = new Map();
|
||||
_nestedChildLists: ChildListCollection<VirtualizedList> =
|
||||
new ChildListCollection();
|
||||
_offsetFromParentVirtualizedList: number = 0;
|
||||
_prevParentOffset: number = 0;
|
||||
// $FlowFixMe[missing-local-annot]
|
||||
@@ -1067,13 +1018,9 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
||||
};
|
||||
|
||||
_triggerRemeasureForChildListsInCell(cellKey: string): void {
|
||||
const childListKeys = this._cellKeysToChildListKeys.get(cellKey);
|
||||
if (childListKeys) {
|
||||
for (let childKey of childListKeys) {
|
||||
const childList = this._nestedChildLists.get(childKey);
|
||||
childList && childList.measureLayoutRelativeToContainingList();
|
||||
}
|
||||
}
|
||||
this._nestedChildLists.forEachInCell(cellKey, childList => {
|
||||
childList.measureLayoutRelativeToContainingList();
|
||||
});
|
||||
}
|
||||
|
||||
measureLayoutRelativeToContainingList(): void {
|
||||
@@ -1107,14 +1054,8 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
||||
|
||||
// If metrics of the scrollView changed, then we triggered remeasure for child list
|
||||
// to ensure VirtualizedList has the right information.
|
||||
this._cellKeysToChildListKeys.forEach(childListKeys => {
|
||||
if (childListKeys) {
|
||||
for (let childKey of childListKeys) {
|
||||
const childList = this._nestedChildLists.get(childKey);
|
||||
childList &&
|
||||
childList.measureLayoutRelativeToContainingList();
|
||||
}
|
||||
}
|
||||
this._nestedChildLists.forEach(childList => {
|
||||
childList.measureLayoutRelativeToContainingList();
|
||||
});
|
||||
}
|
||||
},
|
||||
@@ -1547,7 +1488,7 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
||||
last: Math.min(state.last + renderAhead, getItemCount(data) - 1),
|
||||
};
|
||||
}
|
||||
if (newState && this._nestedChildLists.size > 0) {
|
||||
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
|
||||
@@ -1556,21 +1497,16 @@ class VirtualizedList extends React.PureComponent<Props, State> {
|
||||
// their items.
|
||||
for (let ii = newFirst; ii <= newLast; ii++) {
|
||||
const cellKeyForIndex = this._indicesToKeys.get(ii);
|
||||
const childListKeys =
|
||||
cellKeyForIndex &&
|
||||
this._cellKeysToChildListKeys.get(cellKeyForIndex);
|
||||
if (!childListKeys) {
|
||||
if (cellKeyForIndex == null) {
|
||||
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.hasMore()) {
|
||||
someChildHasMore = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const someChildHasMore = this._nestedChildLists.anyInCell(
|
||||
cellKeyForIndex,
|
||||
childList => childList.hasMore(),
|
||||
);
|
||||
|
||||
if (someChildHasMore) {
|
||||
newState.last = ii;
|
||||
break;
|
||||
@@ -1879,31 +1815,6 @@ class CellRenderer extends React.Component<
|
||||
}
|
||||
}
|
||||
|
||||
function describeNestedLists(childList: {
|
||||
+cellKey: string,
|
||||
+key: string,
|
||||
+ref: VirtualizedList,
|
||||
+parentDebugInfo: ListDebugInfo,
|
||||
+horizontal: boolean,
|
||||
...
|
||||
}) {
|
||||
let trace =
|
||||
'VirtualizedList trace:\n' +
|
||||
` Child (${childList.horizontal ? 'horizontal' : 'vertical'}):\n` +
|
||||
` listKey: ${childList.key}\n` +
|
||||
` cellKey: ${childList.cellKey}`;
|
||||
|
||||
let debugInfo: ?ListDebugInfo = childList.parentDebugInfo;
|
||||
while (debugInfo) {
|
||||
trace +=
|
||||
`\n Parent (${debugInfo.horizontal ? 'horizontal' : 'vertical'}):\n` +
|
||||
` listKey: ${debugInfo.listKey}\n` +
|
||||
` cellKey: ${debugInfo.cellKey}`;
|
||||
debugInfo = debugInfo.parent;
|
||||
}
|
||||
return trace;
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
verticallyInverted: {
|
||||
transform: [{scaleY: -1}],
|
||||
|
||||
@@ -4,25 +4,13 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import {useMemo, useContext} from 'react';
|
||||
|
||||
// Data propagated through nested lists (regardless of orientation) that is
|
||||
// useful for producing diagnostics for usage errors involving nesting (e.g
|
||||
// missing/duplicate keys).
|
||||
export type ListDebugInfo = $ReadOnly<{
|
||||
cellKey: string,
|
||||
listKey: string,
|
||||
parent: ?ListDebugInfo,
|
||||
// We include all ancestors regardless of orientation, so this is not always
|
||||
// identical to the child's orientation.
|
||||
horizontal: boolean,
|
||||
}>;
|
||||
|
||||
type Context = $ReadOnly<{
|
||||
cellKey: ?string,
|
||||
getScrollMetrics: () => {
|
||||
@@ -39,14 +27,11 @@ type Context = $ReadOnly<{
|
||||
getOutermostParentListRef: () => React.ElementRef<typeof React.Component>,
|
||||
registerAsNestedChild: ({
|
||||
cellKey: string,
|
||||
key: string,
|
||||
ref: React.ElementRef<typeof React.Component>,
|
||||
parentDebugInfo: ListDebugInfo,
|
||||
}) => void,
|
||||
unregisterAsNestedChild: ({
|
||||
key: string,
|
||||
ref: React.ElementRef<typeof React.Component>,
|
||||
}) => void,
|
||||
debugInfo: ListDebugInfo,
|
||||
}>;
|
||||
|
||||
export const VirtualizedListContext: React.Context<?Context> =
|
||||
@@ -89,12 +74,6 @@ export function VirtualizedListContextProvider({
|
||||
getOutermostParentListRef: value.getOutermostParentListRef,
|
||||
registerAsNestedChild: value.registerAsNestedChild,
|
||||
unregisterAsNestedChild: value.unregisterAsNestedChild,
|
||||
debugInfo: {
|
||||
cellKey: value.debugInfo.cellKey,
|
||||
horizontal: value.debugInfo.horizontal,
|
||||
listKey: value.debugInfo.listKey,
|
||||
parent: value.debugInfo.parent,
|
||||
},
|
||||
}),
|
||||
[
|
||||
value.getScrollMetrics,
|
||||
@@ -102,10 +81,6 @@ export function VirtualizedListContextProvider({
|
||||
value.getOutermostParentListRef,
|
||||
value.registerAsNestedChild,
|
||||
value.unregisterAsNestedChild,
|
||||
value.debugInfo.cellKey,
|
||||
value.debugInfo.horizontal,
|
||||
value.debugInfo.listKey,
|
||||
value.debugInfo.parent,
|
||||
],
|
||||
);
|
||||
return (
|
||||
|
||||
@@ -167,6 +167,8 @@ type OptionalProps = {|
|
||||
* 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.
|
||||
*
|
||||
* @deprecated no longer used/required
|
||||
*/
|
||||
listKey?: string,
|
||||
/**
|
||||
|
||||
@@ -29,7 +29,6 @@ import type {
|
||||
export type {RenderItemProps, RenderItemType, Separators};
|
||||
|
||||
import {
|
||||
type ListDebugInfo,
|
||||
VirtualizedListCellContextProvider,
|
||||
VirtualizedListContext,
|
||||
VirtualizedListContextProvider,
|
||||
@@ -43,6 +42,7 @@ import * as React from 'react';
|
||||
import {CellRenderMask} from './CellRenderMask';
|
||||
import clamp from '../Utilities/clamp';
|
||||
import StateSafePureComponent from './StateSafePureComponent';
|
||||
import ChildListCollection from './ChildListCollection';
|
||||
|
||||
const RefreshControl = require('../Components/RefreshControl/RefreshControl');
|
||||
const ScrollView = require('../Components/ScrollView/ScrollView');
|
||||
@@ -370,19 +370,6 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
|
||||
return this.context?.cellKey || 'rootList';
|
||||
}
|
||||
|
||||
_getListKey(): string {
|
||||
return this.props.listKey || this._getCellKey();
|
||||
}
|
||||
|
||||
_getDebugInfo(): ListDebugInfo {
|
||||
return {
|
||||
listKey: this._getListKey(),
|
||||
cellKey: this._getCellKey(),
|
||||
horizontal: horizontalOrDefault(this.props.horizontal),
|
||||
parent: this.context?.debugInfo,
|
||||
};
|
||||
}
|
||||
|
||||
// $FlowFixMe[missing-local-annot]
|
||||
_getScrollMetrics = () => {
|
||||
return this._scrollMetrics;
|
||||
@@ -403,41 +390,20 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
|
||||
|
||||
_registerAsNestedChild = (childList: {
|
||||
cellKey: string,
|
||||
key: string,
|
||||
ref: React.ElementRef<typeof React.Component>,
|
||||
parentDebugInfo: ListDebugInfo,
|
||||
...
|
||||
}): void => {
|
||||
const specificRef = ((childList.ref: any): VirtualizedList);
|
||||
// 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);
|
||||
if (existingChildData) {
|
||||
console.error(
|
||||
'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.\n\n' +
|
||||
describeNestedLists({
|
||||
...childList,
|
||||
ref: specificRef,
|
||||
// We're called from the child's componentDidMount, so it's safe to
|
||||
// read the child's props here (albeit weird).
|
||||
horizontal: !!specificRef.props.horizontal,
|
||||
}),
|
||||
);
|
||||
}
|
||||
this._nestedChildLists.set(childList.key, specificRef);
|
||||
|
||||
const listRef = ((childList.ref: any): VirtualizedList);
|
||||
this._nestedChildLists.add(listRef, childList.cellKey);
|
||||
if (this._hasInteracted) {
|
||||
specificRef.recordInteraction();
|
||||
listRef.recordInteraction();
|
||||
}
|
||||
};
|
||||
|
||||
_unregisterAsNestedChild = (childList: {key: string, ...}): void => {
|
||||
this._nestedChildLists.delete(childList.key);
|
||||
_unregisterAsNestedChild = (childList: {
|
||||
ref: React.ElementRef<typeof React.Component>,
|
||||
}): void => {
|
||||
const listRef = ((childList.ref: any): VirtualizedList);
|
||||
this._nestedChildLists.remove(listRef);
|
||||
};
|
||||
|
||||
state: State;
|
||||
@@ -640,7 +606,7 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
|
||||
);
|
||||
}
|
||||
|
||||
if (this._nestedChildLists.size > 0) {
|
||||
if (this._nestedChildLists.size() > 0) {
|
||||
// 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
|
||||
@@ -661,17 +627,13 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
|
||||
_findFirstChildWithMore(first: number, last: number): number | null {
|
||||
for (let ii = first; ii <= last; ii++) {
|
||||
const cellKeyForIndex = this._indicesToKeys.get(ii);
|
||||
const childListKeys =
|
||||
cellKeyForIndex && this._cellKeysToChildListKeys.get(cellKeyForIndex);
|
||||
if (!childListKeys) {
|
||||
continue;
|
||||
}
|
||||
// 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.hasMore()) {
|
||||
return ii;
|
||||
}
|
||||
if (
|
||||
cellKeyForIndex != null &&
|
||||
this._nestedChildLists.anyInCell(cellKeyForIndex, childList =>
|
||||
childList.hasMore(),
|
||||
)
|
||||
) {
|
||||
return ii;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -681,27 +643,15 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
|
||||
componentDidMount() {
|
||||
if (this._isNestedWithSameOrientation()) {
|
||||
this.context.registerAsNestedChild({
|
||||
cellKey: this._getCellKey(),
|
||||
key: this._getListKey(),
|
||||
ref: this,
|
||||
// NOTE: When the child mounts (here) it's not necessarily safe to read
|
||||
// the parent's props. This is why we explicitly propagate debugInfo
|
||||
// "down" via context and "up" again via this method call on the
|
||||
// parent.
|
||||
parentDebugInfo: this.context.debugInfo,
|
||||
cellKey: this.context.cellKey,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this._isNestedWithSameOrientation()) {
|
||||
this.context.unregisterAsNestedChild({
|
||||
key: this._getListKey(),
|
||||
state: {
|
||||
...this.state,
|
||||
frames: this._frames,
|
||||
},
|
||||
});
|
||||
this.context.unregisterAsNestedChild({ref: this});
|
||||
}
|
||||
this._updateCellsToRenderBatcher.dispose({abort: true});
|
||||
this._viewabilityTuples.forEach(tuple => {
|
||||
@@ -1054,7 +1004,6 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
|
||||
getOutermostParentListRef: this._getOutermostParentListRef,
|
||||
registerAsNestedChild: this._registerAsNestedChild,
|
||||
unregisterAsNestedChild: this._unregisterAsNestedChild,
|
||||
debugInfo: this._getDebugInfo(),
|
||||
}}>
|
||||
{React.cloneElement(
|
||||
(
|
||||
@@ -1131,8 +1080,6 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
|
||||
}
|
||||
|
||||
_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: {[string]: null | CellRenderer} = {};
|
||||
_fillRateHelper: FillRateHelper;
|
||||
_frames: {
|
||||
@@ -1154,7 +1101,8 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
|
||||
_highestMeasuredFrameIndex = 0;
|
||||
_indicesToKeys: Map<number, string> = new Map();
|
||||
_lastFocusedCellKey: ?string = null;
|
||||
_nestedChildLists: Map<string, VirtualizedList> = new Map();
|
||||
_nestedChildLists: ChildListCollection<VirtualizedList> =
|
||||
new ChildListCollection();
|
||||
_offsetFromParentVirtualizedList: number = 0;
|
||||
_prevParentOffset: number = 0;
|
||||
// $FlowFixMe[missing-local-annot]
|
||||
@@ -1288,13 +1236,9 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
|
||||
};
|
||||
|
||||
_triggerRemeasureForChildListsInCell(cellKey: string): void {
|
||||
const childListKeys = this._cellKeysToChildListKeys.get(cellKey);
|
||||
if (childListKeys) {
|
||||
for (let childKey of childListKeys) {
|
||||
const childList = this._nestedChildLists.get(childKey);
|
||||
childList && childList.measureLayoutRelativeToContainingList();
|
||||
}
|
||||
}
|
||||
this._nestedChildLists.forEachInCell(cellKey, childList => {
|
||||
childList.measureLayoutRelativeToContainingList();
|
||||
});
|
||||
}
|
||||
|
||||
measureLayoutRelativeToContainingList(): void {
|
||||
@@ -1328,14 +1272,8 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
|
||||
|
||||
// If metrics of the scrollView changed, then we triggered remeasure for child list
|
||||
// to ensure VirtualizedList has the right information.
|
||||
this._cellKeysToChildListKeys.forEach(childListKeys => {
|
||||
if (childListKeys) {
|
||||
for (let childKey of childListKeys) {
|
||||
const childList = this._nestedChildLists.get(childKey);
|
||||
childList &&
|
||||
childList.measureLayoutRelativeToContainingList();
|
||||
}
|
||||
}
|
||||
this._nestedChildLists.forEach(childList => {
|
||||
childList.measureLayoutRelativeToContainingList();
|
||||
});
|
||||
}
|
||||
},
|
||||
@@ -2128,31 +2066,6 @@ class CellRenderer extends React.Component<
|
||||
}
|
||||
}
|
||||
|
||||
function describeNestedLists(childList: {
|
||||
+cellKey: string,
|
||||
+key: string,
|
||||
+ref: VirtualizedList,
|
||||
+parentDebugInfo: ListDebugInfo,
|
||||
+horizontal: boolean,
|
||||
...
|
||||
}) {
|
||||
let trace =
|
||||
'VirtualizedList trace:\n' +
|
||||
` Child (${childList.horizontal ? 'horizontal' : 'vertical'}):\n` +
|
||||
` listKey: ${childList.key}\n` +
|
||||
` cellKey: ${childList.cellKey}`;
|
||||
|
||||
let debugInfo: ?ListDebugInfo = childList.parentDebugInfo;
|
||||
while (debugInfo) {
|
||||
trace +=
|
||||
`\n Parent (${debugInfo.horizontal ? 'horizontal' : 'vertical'}):\n` +
|
||||
` listKey: ${debugInfo.listKey}\n` +
|
||||
` cellKey: ${debugInfo.cellKey}`;
|
||||
debugInfo = debugInfo.parent;
|
||||
}
|
||||
return trace;
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
verticallyInverted: {
|
||||
transform: [{scaleY: -1}],
|
||||
|
||||
@@ -420,74 +420,6 @@ describe('VirtualizedList', () => {
|
||||
expect(onEndReached).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('provides a trace when a listKey collision occurs', () => {
|
||||
const errors = [];
|
||||
jest.spyOn(console, 'error').mockImplementation((...args) => {
|
||||
// Silence the DEV-only React error boundary warning.
|
||||
if ((args[0] || '').startsWith('The above error occurred in the ')) {
|
||||
return;
|
||||
}
|
||||
errors.push(args);
|
||||
});
|
||||
const commonProps = {
|
||||
data: [{key: 'cell0'}],
|
||||
getItem: (data, index) => data[index],
|
||||
getItemCount: data => data.length,
|
||||
renderItem: ({item}) => <item value={item.key} />,
|
||||
};
|
||||
try {
|
||||
ReactTestRenderer.create(
|
||||
<VirtualizedList
|
||||
{...commonProps}
|
||||
horizontal={false}
|
||||
listKey="level0"
|
||||
renderItem={() => (
|
||||
<VirtualizedList
|
||||
{...commonProps}
|
||||
horizontal={true}
|
||||
listKey="level1"
|
||||
renderItem={() => (
|
||||
<>
|
||||
{/* Force a collision */}
|
||||
<VirtualizedList
|
||||
{...commonProps}
|
||||
horizontal={true}
|
||||
listKey="level2"
|
||||
/>
|
||||
<VirtualizedList
|
||||
{...commonProps}
|
||||
horizontal={true}
|
||||
listKey="level2"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
/>,
|
||||
);
|
||||
expect(errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
"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.
|
||||
|
||||
VirtualizedList trace:
|
||||
Child (horizontal):
|
||||
listKey: level2
|
||||
cellKey: cell0
|
||||
Parent (horizontal):
|
||||
listKey: level1
|
||||
cellKey: cell0
|
||||
Parent (vertical):
|
||||
listKey: level0
|
||||
cellKey: rootList",
|
||||
],
|
||||
]
|
||||
`);
|
||||
} finally {
|
||||
console.error.mockRestore();
|
||||
}
|
||||
});
|
||||
|
||||
it('throws if using scrollToIndex with index less than 0', () => {
|
||||
const component = ReactTestRenderer.create(
|
||||
<VirtualizedList
|
||||
|
||||
Reference in New Issue
Block a user