import { useReducer, useState } from 'react'; export type State = { value: T | undefined; error: undefined } | { value: false; error: Error }; type Action = | { type: 'RESOLVE'; value: T } | { type: 'REJECT'; error: Error } | { type: 'RESET' }; function reducer(state: State, action: Action): State { switch (action.type) { case 'RESOLVE': return { value: action.value, error: undefined }; case 'REJECT': return { value: false, error: action.error }; case 'RESET': return { value: undefined, error: undefined }; default: return state; } } export default function useResolver(resetKey?: unknown): [State, React.Dispatch>] { const [previousResetKey, setPreviousResetKey] = useState(() => resetKey); const [state, dispatch] = useReducer(reducer, { value: undefined, error: undefined }); // Reset before effects can report a result belonging to the previous input. if (!Object.is(previousResetKey, resetKey)) { setPreviousResetKey(() => resetKey); dispatch({ type: 'RESET' }); } return [state, dispatch]; }