Skip to content

Commit

Permalink
Fix virtualized cell keys for list headers and footers
Browse files Browse the repository at this point in the history
Summary:
The change enabling virtualization in nested lists contained a hidden assumption that nested lists would only appear within the *cells* of a parent list.

If a list header or footer component contains a `VirtualizedList`, that child list won't be wrapped in a `CellRenderer` component and therefore won't have access to `virtualizedCellRenderer` through its context. This causes an error when the child list tries to access the `cellKey` property on an undefined object.

This change wraps the header/footer views in a `VirtualizedCellWrapper` component which supplies that context properly.

Reviewed By: sahrens

Differential Revision: D6603342

fbshipit-source-id: 4d2d82f04947048a16ec9968121d8ecc8c95655a
  • Loading branch information
logandaniels authored and facebook-github-bot committed Dec 19, 2017
1 parent f1055bc commit a010a0c
Showing 1 changed file with 50 additions and 24 deletions.
74 changes: 50 additions & 24 deletions Libraries/Lists/VirtualizedList.js
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ class VirtualizedList extends React.PureComponent<Props, State> {
};

static contextTypes = {
virtualizedListCellRenderer: PropTypes.shape({
virtualizedCell: PropTypes.shape({
cellKey: PropTypes.string,
}),
virtualizedList: PropTypes.shape({
Expand Down Expand Up @@ -466,6 +466,13 @@ class VirtualizedList extends React.PureComponent<Props, State> {
};
}

_getCellKey(): string {
return (
(this.context.virtualizedCell && this.context.virtualizedCell.cellKey) ||
'rootList'
);
}

_getScrollMetrics = () => {
return this._scrollMetrics;
};
Expand Down Expand Up @@ -559,10 +566,8 @@ class VirtualizedList extends React.PureComponent<Props, State> {

if (this._isNestedWithSameOrientation()) {
const storedState = this.context.virtualizedList.registerAsNestedChild({
cellKey: this.context.virtualizedListCellRenderer.cellKey,
key:
this.props.listKey ||
this.context.virtualizedListCellRenderer.cellKey,
cellKey: this._getCellKey(),
key: this.props.listKey || this._getCellKey(),
ref: this,
});
if (storedState) {
Expand All @@ -575,8 +580,6 @@ class VirtualizedList extends React.PureComponent<Props, State> {
this.state = initialState;
}

componentWillMount() {}

componentDidMount() {
if (this.props.initialScrollIndex) {
this._initialScrollIndexTimeout = setTimeout(
Expand All @@ -593,9 +596,7 @@ class VirtualizedList extends React.PureComponent<Props, State> {
componentWillUnmount() {
if (this._isNestedWithSameOrientation()) {
this.context.virtualizedList.unregisterAsNestedChild({
key:
this.props.listKey ||
this.context.virtualizedListCellRenderer.cellKey,
key: this.props.listKey || this._getCellKey(),
state: {
first: this.state.first,
last: this.state.last,
Expand Down Expand Up @@ -743,12 +744,13 @@ class VirtualizedList extends React.PureComponent<Props, State> {
<ListHeaderComponent />
);
cells.push(
<View
key="$header"
onLayout={this._onLayoutHeader}
style={inversionStyle}>
{element}
</View>,
<VirtualizedCellWrapper
cellKey={this._getCellKey() + '-header'}
key="$header">
<View onLayout={this._onLayoutHeader} style={inversionStyle}>
{element}
</View>
</VirtualizedCellWrapper>,
);
}
const itemCount = this.props.getItemCount(data);
Expand Down Expand Up @@ -867,12 +869,13 @@ class VirtualizedList extends React.PureComponent<Props, State> {
<ListFooterComponent />
);
cells.push(
<View
key="$footer"
onLayout={this._onLayoutFooter}
style={inversionStyle}>
{element}
</View>,
<VirtualizedCellWrapper
cellKey={this._getCellKey() + '-footer'}
key="$footer">
<View onLayout={this._onLayoutFooter} style={inversionStyle}>
{element}
</View>
</VirtualizedCellWrapper>,
);
}
const scrollProps = {
Expand Down Expand Up @@ -1522,14 +1525,14 @@ class CellRenderer extends React.Component<
};

static childContextTypes = {
virtualizedListCellRenderer: PropTypes.shape({
virtualizedCell: PropTypes.shape({
cellKey: PropTypes.string,
}),
};

getChildContext() {
return {
virtualizedListCellRenderer: {
virtualizedCell: {
cellKey: this.props.cellKey,
},
};
Expand Down Expand Up @@ -1621,6 +1624,29 @@ class CellRenderer extends React.Component<
}
}

class VirtualizedCellWrapper extends React.Component<{
cellKey: string,
children: React.Node,
}> {
static childContextTypes = {
virtualizedCell: PropTypes.shape({
cellKey: PropTypes.string,
}),
};

getChildContext() {
return {
virtualizedCell: {
cellKey: this.props.cellKey,
},
};
}

render() {
return this.props.children;
}
}

const styles = StyleSheet.create({
verticallyInverted: {
transform: [{scaleY: -1}],
Expand Down

0 comments on commit a010a0c

Please sign in to comment.