Skip to content

Instantly share code, notes, and snippets.

@Gaya
Created July 19, 2019 10:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Gaya/d8629829c07980d1cd131ad1c87e109d to your computer and use it in GitHub Desktop.
Save Gaya/d8629829c07980d1cd131ad1c87e109d to your computer and use it in GitHub Desktop.
import { useEffect, useReducer } from 'react';
type PromiseState<T> = {
isPending: false;
isResolved: false;
isError: false;
} | {
isPending: true;
isResolved: false;
isError: false;
} | {
isPending: false;
isResolved: true;
isError: true;
error: Error;
} | {
isPending: false;
isResolved: true;
isError: false;
value: T;
};
interface Reset {
type: 'RESET';
}
interface StartResolve {
type: 'START_RESOLVE';
}
interface ReceiveResult<T> {
type: 'RECEIVE_RESULT';
result: T;
}
interface ResultFailed {
type: 'RESULT_FAILED';
error: Error;
}
type PromiseActions<T> = Reset | StartResolve | ReceiveResult<T> | ResultFailed;
function usePromise<T>(
toResolve: () => Promise<T>,
): PromiseState<T> {
const [state, dispatch] = useReducer(
(state: PromiseState<T>, action: PromiseActions<T>): PromiseState<T> => {
switch (action.type) {
case 'START_RESOLVE':
return {
isPending: true,
isResolved: false,
isError: false,
};
case 'RECEIVE_RESULT':
return {
isPending: false,
isResolved: true,
isError: false,
value: action.result,
};
case 'RESULT_FAILED':
return {
isPending: false,
isResolved: true,
isError: true,
error: action.error,
};
case 'RESET':
return {
isPending: false,
isResolved: false,
isError: false,
};
default:
return state;
}
},
{
isPending: false,
isResolved: false,
isError: false,
},
);
useEffect(
() => dispatch({ type: 'RESET' }),
[toResolve]
);
useEffect(
() => {
if (!state.isPending && !state.isResolved) {
dispatch({ type: 'START_RESOLVE' });
toResolve()
.then(result => dispatch({ type: 'RECEIVE_RESULT', result }))
.catch(error => dispatch({ type: 'RESULT_FAILED', error }));
}
},
[toResolve, state.isPending, state.isResolved],
);
return state;
}
export default usePromise;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment