Skip to content

Instantly share code, notes, and snippets.

@AudyOdi
Created September 21, 2018 09:53
Show Gist options
  • Select an option

  • Save AudyOdi/a64f3e12bcedc70a937be61877afcff9 to your computer and use it in GitHub Desktop.

Select an option

Save AudyOdi/a64f3e12bcedc70a937be61877afcff9 to your computer and use it in GitHub Desktop.
// @flow
import React, {type Node} from 'react';
import {View} from 'react-native';
import ActivityIndicator from './ActivityIndicator';
type FetchResult = {
name: string,
result: *,
};
type FetchConfiguration = {
showLoadingIndicator?: boolean,
};
type FetchFunction = {
name: string,
fetch: (args: *, config?: FetchConfiguration) => *,
onFailed?: (errorMessage: string) => void,
onSuccess?: (args: *) => void,
};
export type FetchAll = (args?: *, config?: FetchConfiguration) => Promise<*>;
export type Fetch = (
name: string,
args?: *,
config?: FetchConfiguration,
) => Promise<*>;
type Props = {
fetchList: Array<FetchFunction>,
loadingComponent?: Node,
fetchOnDidMount?: boolean,
renderLoading?: boolean,
loadingComponentStyle?: StyleSet,
children: ({
resultList: Array<FetchResult>,
isLoading: boolean,
errorMessage: ?string,
fetchAll: FetchAll,
fetch: Fetch,
resetError: () => void,
}) => Node,
};
type State = {
isLoading: boolean,
resultList: Array<FetchResult>,
errorMessage: ?string,
};
const INITIAL_CONFIG: FetchConfiguration = {
showLoadingIndicator: true,
};
export default class Fetcher extends React.Component<Props, State> {
state = {
isLoading:
this.props.fetchOnDidMount != null ? this.props.fetchOnDidMount : true,
resultList: [],
errorMessage: null,
};
componentDidMount() {
let {fetchOnDidMount = true} = this.props;
fetchOnDidMount && this._executeFetchList();
}
render() {
let {
loadingComponent,
renderLoading = true,
loadingComponentStyle,
children,
} = this.props;
let {isLoading, resultList, errorMessage} = this.state;
if (renderLoading && isLoading) {
return (
loadingComponent || (
<DefaultLoadingIndicator style={loadingComponentStyle} />
)
);
}
return children({
resultList,
isLoading,
errorMessage,
fetchAll: this._executeFetchList,
fetch: this._fetchFunc,
resetError: this._resetError,
});
}
_resetError = () => {
this.setState({errorMessage: null});
};
_fetchFunc = async (
name: string,
args: any,
config?: FetchConfiguration = INITIAL_CONFIG,
) => {
let {fetchList} = this.props;
let {resultList} = this.state;
this.setState({
isLoading: config.showLoadingIndicator,
errorMessage: null,
});
let refetchFuncIndex = fetchList.findIndex(
(fetchItem) => fetchItem.name === name,
);
if (refetchFuncIndex < 0) {
return;
}
let refetchFunc = fetchList[refetchFuncIndex];
try {
let result = await refetchFunc.fetch(args);
resultList[refetchFuncIndex] = {
name,
result,
};
this.setState({resultList, isLoading: false, errorMessage: null});
refetchFunc.onSuccess && refetchFunc.onSuccess(result);
} catch (error) {
let {message} = error;
this.setState({
errorMessage: message,
isLoading: false,
});
refetchFunc.onFailed && refetchFunc.onFailed(message);
}
};
_executeFetchList = async (
args: *,
config?: FetchConfiguration = INITIAL_CONFIG,
) => {
let {fetchList} = this.props;
let resultList = [];
let success = true;
this.setState({
isLoading: config.showLoadingIndicator,
errorMessage: null,
});
for (let fetchItem of fetchList) {
let prevResult = resultList[resultList.length - 1];
try {
let result = await fetchItem.fetch(
(prevResult && prevResult.result) || null,
);
resultList.push({name: fetchItem.name, result});
fetchItem.onSuccess && fetchItem.onSuccess(result);
} catch (error) {
let {message} = error;
this.setState({
errorMessage: message,
isLoading: false,
});
fetchItem.onFailed && fetchItem.onFailed(message);
success = false;
break;
}
}
success &&
this.setState({resultList, isLoading: false, errorMessage: null});
};
}
type LoadingIndicatorProps = {
style?: ?StyleSet,
};
export function DefaultLoadingIndicator(props: LoadingIndicatorProps) {
let {style} = props;
return (
<View
style={[
{
justifyContent: 'center',
alignItems: 'center',
},
style,
]}
>
<ActivityIndicator />
</View>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment