Skip to content

Instantly share code, notes, and snippets.

@ecwyne
Created October 12, 2019 21:23
Show Gist options
  • Save ecwyne/5b66117358b3c5d87c0233dbab20d68e to your computer and use it in GitHub Desktop.
Save ecwyne/5b66117358b3c5d87c0233dbab20d68e to your computer and use it in GitHub Desktop.
import { useState, useEffect, useCallback } from 'react';
type AsyncState<TData, TError = Error> = {
status: 'idle' | 'loading' | 'finished' | 'failed';
data?: TData;
error?: TError;
};
type AsyncOptions<TArgs> = {
onLoad?: boolean;
args?: TArgs;
};
const useAsync = <TData, TArgs extends any[]>(
asyncFn: (...args: TArgs) => Promise<TData>,
options?: AsyncOptions<TArgs>,
) => {
if (options && !options.args) {
options.args = [] as TArgs;
}
const [state, setState] = useState<AsyncState<TData>>({
status: 'idle',
});
const run = useCallback((...args: TArgs) => {
setState(state => ({
...state,
status: 'loading',
}));
asyncFn(...args)
.then(data =>
setState({
data,
status: 'finished',
error: undefined,
}),
)
.catch(error => {
setState(state => ({
...state,
status: 'failed',
error,
}));
});
}, []);
useEffect(() => {
if (options && options.onLoad) {
run(...options.args);
}
}, []);
return {
run,
status: state.status,
data: state.data,
error: state.error,
isLoading: state.status === 'loading',
isFinished: state.status === 'finished',
};
};
const sayHello = () => Promise.resolve('Hello!');
const sayHelloWithName = (name: string) => Promise.resolve(`Hello ${name}`);
const { data } = useAsync(sayHello, { onLoad: true });
const { data: secondData } = useAsync(sayHelloWithName, {
onLoad: true,
args: ['Ana'],
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment