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 https://github.com/facebook/react-native/pull/18206 Differential Revision: D7266274 Pulled By: sahrens fbshipit-source-id: 4636d2418474a4c86ac63e5e18a9afc391a518c5
This commit is contained in:
parent
9737774b96
commit
db061ea8c7
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue