Skip to content

Commit

Permalink
Don't wrap ListEmptyComponent in an extra view
Browse files Browse the repository at this point in the history
Summary:
A common UI pattern for list empty states is some text/images centered inside the visible part of the list. This is pretty hard to do currently because we wrap ListEmptyComponent with an extra view with no way to style it so we cannot just use `flex: 1` to make it fill the available space.

- Added an example of ListEmptyComponent in the FlatList example in RNTester

Before (no way to make ListEmptyComponent fill the space):
<img width="377" alt="screen shot 2018-03-05 at 5 24 15 pm" src="https://user-images.githubusercontent.com/2677334/37003152-129db3ac-209a-11e8-9600-110f10d57144.png">

After:
<img width="377" alt="screen shot 2018-03-05 at 5 09 20 pm" src="https://user-images.githubusercontent.com/2677334/37002809-e6971178-2098-11e8-8cf7-74bfb2f6a992.png">

- Tested some edge cases like returning null from the ListEmptyComponent

- Tested in an app that uses FlatList + ListEmptyComponent

[GENERAL] [MINOR] [VirtualizedList] - Don't wrap ListEmptyComponent in an extra view
Closes #18206

Differential Revision: D7266274

Pulled By: sahrens

fbshipit-source-id: 4636d2418474a4c86ac63e5e18a9afc391a518c5
  • Loading branch information
janicduplessis authored and facebook-github-bot committed Mar 14, 2018
1 parent 9737774 commit db061ea
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 20 deletions.
26 changes: 14 additions & 12 deletions Libraries/Lists/VirtualizedList.js
Original file line number Diff line number Diff line change
Expand Up @@ -850,23 +850,25 @@ class VirtualizedList extends React.PureComponent<Props, State> {
);
}
} else if (ListEmptyComponent) {
const element = React.isValidElement(ListEmptyComponent) ? (
const element: React.Element<any> = (React.isValidElement(
ListEmptyComponent,
) ? (
ListEmptyComponent
) : (
// $FlowFixMe
<ListEmptyComponent />
);
): any);
cells.push(
<View
key="$empty"
onLayout={this._onLayoutEmpty}
style={inversionStyle}>
{/*
Flow doesn't know this is a React.Element and not a React.Component
$FlowFixMe https://fburl.com/b9xmtm09
*/}
{element}
</View>,
React.cloneElement(element, {
key: '$empty',
onLayout: event => {
this._onLayoutEmpty(event);
if (element.props.onLayout) {
element.props.onLayout(event);
}
},
style: [element.props.style, inversionStyle],
}),
);
}
if (ListFooterComponent) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -683,12 +683,7 @@ exports[`VirtualizedList renders empty list with empty component 1`] = `
>
<header />
</View>
<View
onLayout={[Function]}
style={null}
>
<empty />
</View>
<empty />
<View
onLayout={[Function]}
style={null}
Expand Down
9 changes: 7 additions & 2 deletions RNTester/js/FlatListExample.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const {
FooterComponent,
HeaderComponent,
ItemComponent,
ListEmptyComponent,
ItemSeparatorComponent,
PlainInput,
SeparatorComponent,
Expand Down Expand Up @@ -58,6 +59,7 @@ class FlatListExample extends React.PureComponent<{}, $FlowFixMeState> {
fixedHeight: true,
logViewable: false,
virtualized: true,
empty: false,
};

_onChangeFilterText = (filterText) => {
Expand Down Expand Up @@ -109,8 +111,9 @@ class FlatListExample extends React.PureComponent<{}, $FlowFixMeState> {
{renderSmallSwitchOption(this, 'virtualized')}
{renderSmallSwitchOption(this, 'horizontal')}
{renderSmallSwitchOption(this, 'fixedHeight')}
{renderSmallSwitchOption(this, 'logViewable')}
{renderSmallSwitchOption(this, 'log')}
{renderSmallSwitchOption(this, 'inverted')}
{renderSmallSwitchOption(this, 'empty')}
{renderSmallSwitchOption(this, 'debug')}
<Spindicator value={this._scrollPos} />
</View>
Expand All @@ -120,7 +123,8 @@ class FlatListExample extends React.PureComponent<{}, $FlowFixMeState> {
ItemSeparatorComponent={ItemSeparatorComponent}
ListHeaderComponent={<HeaderComponent />}
ListFooterComponent={FooterComponent}
data={filteredData}
ListEmptyComponent={ListEmptyComponent}
data={this.state.empty ? [] : filteredData}
debug={this.state.debug}
disableVirtualization={!this.state.virtualized}
getItemLayout={this.state.fixedHeight ?
Expand Down Expand Up @@ -210,6 +214,7 @@ const styles = StyleSheet.create({
},
list: {
backgroundColor: 'white',
flexGrow: 1,
},
options: {
flexDirection: 'row',
Expand Down
16 changes: 16 additions & 0 deletions RNTester/js/ListExampleShared.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,16 @@ class HeaderComponent extends React.PureComponent<{}> {
}
}

class ListEmptyComponent extends React.PureComponent<{}> {
render() {
return (
<View style={styles.listEmpty}>
<Text>The list is empty :o</Text>
</View>
);
}
}

class SeparatorComponent extends React.PureComponent<{}> {
render() {
return <View style={styles.separator} />;
Expand Down Expand Up @@ -240,6 +250,11 @@ const styles = StyleSheet.create({
headerFooterContainer: {
backgroundColor: 'rgb(239, 239, 244)',
},
listEmpty: {
alignItems: 'center',
justifyContent: 'center',
flexGrow: 1,
},
horizItem: {
alignSelf: 'flex-start', // Necessary for touch highlight
},
Expand Down Expand Up @@ -317,6 +332,7 @@ const styles = StyleSheet.create({
module.exports = {
FooterComponent,
HeaderComponent,
ListEmptyComponent,
ItemComponent,
ItemSeparatorComponent,
PlainInput,
Expand Down

0 comments on commit db061ea

Please sign in to comment.