Permalink
Browse files

Don't wrap ListEmptyComponent in an extra view

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 db061ea8c7b78d7e9df4a450c9e7a24d9b2382b4
@@ -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) {
@@ -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}
@@ -27,6 +27,7 @@ const {
FooterComponent,
HeaderComponent,
ItemComponent,
ListEmptyComponent,
ItemSeparatorComponent,
PlainInput,
SeparatorComponent,
@@ -58,6 +59,7 @@ class FlatListExample extends React.PureComponent<{}, $FlowFixMeState> {
fixedHeight: true,
logViewable: false,
virtualized: true,
empty: false,
};
_onChangeFilterText = (filterText) => {
@@ -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>
@@ -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 ?
@@ -210,6 +214,7 @@ const styles = StyleSheet.create({
},
list: {
backgroundColor: 'white',
flexGrow: 1,
},
options: {
flexDirection: 'row',
@@ -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} />;
@@ -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
},
@@ -317,6 +332,7 @@ const styles = StyleSheet.create({
module.exports = {
FooterComponent,
HeaderComponent,
ListEmptyComponent,
ItemComponent,
ItemSeparatorComponent,
PlainInput,

0 comments on commit db061ea

Please sign in to comment.