Created
July 19, 2021 03:12
-
-
Save yomybaby/d2e5e6edc8037500668d03087bc8221c to your computer and use it in GitHub Desktop.
React hook for handling promise pattern
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useReducer, useCallback } from 'react'; | |
export type Service<R, P extends any[]> = (...args: P) => Promise<R>; | |
export type RequestState<R, P> = { | |
data?: R; | |
error?: any; | |
pending: boolean; | |
fulfilled: boolean; | |
rejected: boolean; | |
runArgs?: P; | |
}; | |
export type RequestAction<R, P> = | |
| { type: 'request'; payload: P } | |
| { type: 'success'; payload: R } | |
| { type: 'failure'; payload: string }; | |
function createReducer<R, P>() { | |
return function reducer( | |
state: RequestState<R, P>, | |
action: RequestAction<R, P> | |
): RequestState<R, P> { | |
switch (action.type) { | |
case 'request': | |
return { | |
...state, | |
error: null, | |
pending: true, | |
fulfilled: false, | |
rejected: false, | |
runArgs: action.payload, | |
}; | |
case 'success': | |
return { | |
data: action.payload, | |
error: null, | |
pending: false, | |
fulfilled: true, | |
rejected: false, | |
}; | |
case 'failure': | |
return { | |
...state, | |
error: action.payload, | |
pending: false, | |
fulfilled: false, | |
rejected: true, | |
}; | |
} | |
}; | |
} | |
export function useRequest<R, P extends any[]>( | |
asyncTask: Service<R, P>, | |
options?: { | |
// autoFirstRun?: boolean; | |
// passArgs?: P; | |
} | |
) { | |
// const {autoFirstRun = false, passArgs} = options || {}; | |
const reducer = createReducer<R, P>(); | |
const [state, dispatch] = useReducer< | |
React.Reducer<RequestState<R, P>, RequestAction<R, P>> | |
>(reducer, { | |
// data: null, | |
// error: null, | |
pending: false, | |
fulfilled: false, | |
rejected: false, | |
}); | |
const requestActions = { | |
run: useCallback( | |
async (...args: P) => { | |
dispatch({ | |
type: 'request', | |
payload: args, | |
}); | |
try { | |
// then 패턴 데신에 await을 쓴 이유는 일반 함수일 경우에도 동작하도록 | |
const data = await asyncTask(...args); | |
dispatch({ | |
type: 'success', | |
payload: data, | |
}); | |
return data; | |
} catch (e) { | |
dispatch({ | |
type: 'failure', | |
payload: e, | |
}); | |
throw e; | |
} | |
}, | |
// eslint-disable-next-line react-hooks/exhaustive-deps | |
[dispatch] | |
), | |
}; | |
return [state, requestActions] as const; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment