Use flatlist empty list render to display errors and loading

This commit is contained in:
Arnaud Vergnet 2020-04-03 14:28:33 +02:00
parent 94d2db97ad
commit 784872ed96
3 changed files with 19 additions and 122 deletions

View file

@ -7,7 +7,6 @@ import {MaterialCommunityIcons} from "@expo/vector-icons";
import i18n from 'i18n-js'; import i18n from 'i18n-js';
type Props = { type Props = {
navigation: Object,
message: string, message: string,
icon: string, icon: string,
onRefresh: Function, onRefresh: Function,

View file

@ -1,54 +0,0 @@
import * as React from 'react';
import {ActivityIndicator, Subheading, withTheme} from 'react-native-paper';
import {StyleSheet, View} from "react-native";
import {MaterialCommunityIcons} from "@expo/vector-icons";
/**
* Component used to display a message when a list is empty
*
* @param props Props to pass to the component
* @return {*}
*/
function EmptyWebSectionListItem(props: { text: string, icon: string, refreshing: boolean, theme: {} }) {
const {colors} = props.theme;
return (
<View>
<View style={styles.iconContainer}>
{props.refreshing ?
<ActivityIndicator
animating={true}
size={'large'}
color={colors.primary}/>
:
<MaterialCommunityIcons
name={props.icon}
size={100}
color={colors.textDisabled}/>}
</View>
<Subheading style={{
...styles.subheading,
color: colors.textDisabled
}}>
{props.text}
</Subheading>
</View>
);
}
const styles = StyleSheet.create({
iconContainer: {
justifyContent: 'center',
alignItems: 'center',
width: '100%',
height: 100,
marginBottom: 20
},
subheading: {
textAlign: 'center',
marginRight: 20,
marginLeft: 20,
}
});
export default withTheme(EmptyWebSectionListItem);

View file

@ -5,7 +5,8 @@ import {readData} from "../../utils/WebData";
import i18n from "i18n-js"; import i18n from "i18n-js";
import {Snackbar} from 'react-native-paper'; import {Snackbar} from 'react-native-paper';
import {RefreshControl, SectionList, View} from "react-native"; import {RefreshControl, SectionList, View} from "react-native";
import EmptyWebSectionListItem from "./EmptyWebSectionListItem"; import NetworkErrorComponent from "../Custom/NetworkErrorComponent";
import BasicLoadingScreen from "../Custom/BasicLoadingScreen";
type Props = { type Props = {
navigation: Object, navigation: Object,
@ -22,7 +23,7 @@ type Props = {
type State = { type State = {
refreshing: boolean, refreshing: boolean,
firstLoading: boolean, firstLoading: boolean,
fetchedData: Object, fetchedData: ?Object,
snackbarVisible: boolean snackbarVisible: boolean
}; };
@ -48,14 +49,13 @@ export default class WebSectionList extends React.PureComponent<Props, State> {
state = { state = {
refreshing: false, refreshing: false,
firstLoading: true, firstLoading: true,
fetchedData: {}, fetchedData: undefined,
snackbarVisible: false snackbarVisible: false
}; };
onRefresh: Function; onRefresh: Function;
onFetchSuccess: Function; onFetchSuccess: Function;
onFetchError: Function; onFetchError: Function;
getEmptyRenderItem: Function;
getEmptySectionHeader: Function; getEmptySectionHeader: Function;
showSnackBar: Function; showSnackBar: Function;
hideSnackBar: Function; hideSnackBar: Function;
@ -66,7 +66,6 @@ export default class WebSectionList extends React.PureComponent<Props, State> {
this.onRefresh = this.onRefresh.bind(this); this.onRefresh = this.onRefresh.bind(this);
this.onFetchSuccess = this.onFetchSuccess.bind(this); this.onFetchSuccess = this.onFetchSuccess.bind(this);
this.onFetchError = this.onFetchError.bind(this); this.onFetchError = this.onFetchError.bind(this);
this.getEmptyRenderItem = this.getEmptyRenderItem.bind(this);
this.getEmptySectionHeader = this.getEmptySectionHeader.bind(this); this.getEmptySectionHeader = this.getEmptySectionHeader.bind(this);
this.showSnackBar = this.showSnackBar.bind(this); this.showSnackBar = this.showSnackBar.bind(this);
this.hideSnackBar = this.hideSnackBar.bind(this); this.hideSnackBar = this.hideSnackBar.bind(this);
@ -123,7 +122,7 @@ export default class WebSectionList extends React.PureComponent<Props, State> {
*/ */
onFetchError() { onFetchError() {
this.setState({ this.setState({
fetchedData: {}, fetchedData: undefined,
refreshing: false, refreshing: false,
firstLoading: false firstLoading: false
}); });
@ -157,57 +156,6 @@ export default class WebSectionList extends React.PureComponent<Props, State> {
return <View/>; return <View/>;
} }
/**
* Gets an empty render item
*
* @param item The data to display
* @return {*}
*/
getEmptyRenderItem({item}: Object) {
return (
<EmptyWebSectionListItem
text={item.text}
icon={item.icon}
refreshing={this.state.refreshing}
/>
);
}
/**
* Creates an empty dataset
*
* @return {*}
*/
createEmptyDataset() {
return [
{
title: '',
data: [
{
text: this.state.refreshing ?
i18n.t('general.loading') :
i18n.t('general.networkError'),
isSpinner: this.state.refreshing,
icon: this.state.refreshing ?
'refresh' :
'access-point-network-off'
}
],
keyExtractor: this.datasetKeyExtractor,
}
];
}
/**
* Extracts a key from the given item
*
* @param item The item to extract the key from
* @return {string} The extracted key
*/
datasetKeyExtractor(item: Object): string {
return item.text
}
/** /**
* Shows the error popup * Shows the error popup
*/ */
@ -223,11 +171,10 @@ export default class WebSectionList extends React.PureComponent<Props, State> {
} }
render() { render() {
let dataset = this.props.createDataset(this.state.fetchedData); let dataset = [];
const isEmpty = dataset[0].data.length === 0; if (this.state.fetchedData !== undefined)
const shouldRenderHeader = !isEmpty && (this.props.renderSectionHeader !== null); dataset = this.props.createDataset(this.state.fetchedData);
if (isEmpty) const shouldRenderHeader = this.props.renderSectionHeader !== null;
dataset = this.createEmptyDataset();
return ( return (
<View> <View>
<Snackbar <Snackbar
@ -241,6 +188,7 @@ export default class WebSectionList extends React.PureComponent<Props, State> {
> >
{i18n.t("homeScreen.listUpdateFail")} {i18n.t("homeScreen.listUpdateFail")}
</Snackbar> </Snackbar>
{/*$FlowFixMe*/}
<SectionList <SectionList
sections={dataset} sections={dataset}
refreshControl={ refreshControl={
@ -252,12 +200,16 @@ export default class WebSectionList extends React.PureComponent<Props, State> {
//$FlowFixMe //$FlowFixMe
renderSectionHeader={shouldRenderHeader ? this.props.renderSectionHeader : this.getEmptySectionHeader} renderSectionHeader={shouldRenderHeader ? this.props.renderSectionHeader : this.getEmptySectionHeader}
//$FlowFixMe //$FlowFixMe
renderItem={isEmpty ? this.getEmptyRenderItem : this.props.renderItem} renderItem={this.props.renderItem}
style={{minHeight: 300, width: '100%'}}
stickySectionHeadersEnabled={this.props.stickyHeader} stickySectionHeadersEnabled={this.props.stickyHeader}
contentContainerStyle={ contentContainerStyle={{minHeight: '100%'}}
isEmpty ? style={{minHeight: '100%'}}
{flexGrow: 1, justifyContent: 'center', alignItems: 'center'} : {} ListEmptyComponent={this.state.refreshing
? <BasicLoadingScreen/>
: <NetworkErrorComponent
message={i18n.t('general.networkError')}
icon={"access-point-network-off"}
onRefresh={this.onRefresh}/>
} }
/> />
</View> </View>