From db061ea8c7b78d7e9df4a450c9e7a24d9b2382b4 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Tue, 13 Mar 2018 17:57:36 -0700 Subject: [PATCH] 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): screen shot 2018-03-05 at 5 24 15 pm After: screen shot 2018-03-05 at 5 09 20 pm - 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 https://github.com/facebook/react-native/pull/18206 Differential Revision: D7266274 Pulled By: sahrens fbshipit-source-id: 4636d2418474a4c86ac63e5e18a9afc391a518c5 --- Libraries/Lists/VirtualizedList.js | 26 ++++++++++--------- .../VirtualizedList-test.js.snap | 7 +---- RNTester/js/FlatListExample.js | 9 +++++-- RNTester/js/ListExampleShared.js | 16 ++++++++++++ 4 files changed, 38 insertions(+), 20 deletions(-) diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index 58fe055a3..8ee3da2ea 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -850,23 +850,25 @@ class VirtualizedList extends React.PureComponent { ); } } else if (ListEmptyComponent) { - const element = React.isValidElement(ListEmptyComponent) ? ( + const element: React.Element = (React.isValidElement( + ListEmptyComponent, + ) ? ( ListEmptyComponent ) : ( // $FlowFixMe - ); + ): any); cells.push( - - {/* - Flow doesn't know this is a React.Element and not a React.Component - $FlowFixMe https://fburl.com/b9xmtm09 - */} - {element} - , + 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) { diff --git a/Libraries/Lists/__tests__/__snapshots__/VirtualizedList-test.js.snap b/Libraries/Lists/__tests__/__snapshots__/VirtualizedList-test.js.snap index 7ebe23df2..9cf5c2d9e 100644 --- a/Libraries/Lists/__tests__/__snapshots__/VirtualizedList-test.js.snap +++ b/Libraries/Lists/__tests__/__snapshots__/VirtualizedList-test.js.snap @@ -683,12 +683,7 @@ exports[`VirtualizedList renders empty list with empty component 1`] = ` >
- - - + { 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')} @@ -120,7 +123,8 @@ class FlatListExample extends React.PureComponent<{}, $FlowFixMeState> { ItemSeparatorComponent={ItemSeparatorComponent} ListHeaderComponent={} 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', diff --git a/RNTester/js/ListExampleShared.js b/RNTester/js/ListExampleShared.js index c5eef14db..75ef6bb4b 100644 --- a/RNTester/js/ListExampleShared.js +++ b/RNTester/js/ListExampleShared.js @@ -117,6 +117,16 @@ class HeaderComponent extends React.PureComponent<{}> { } } +class ListEmptyComponent extends React.PureComponent<{}> { + render() { + return ( + + The list is empty :o + + ); + } +} + class SeparatorComponent extends React.PureComponent<{}> { render() { return ; @@ -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,