Last active
October 27, 2018 02:40
-
-
Save punmechanic/309fccd2b0db424eb9ef1470f322e410 to your computer and use it in GitHub Desktop.
Creates generic container components for fetching asynchronous data
This file contains hidden or 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 * as React from "react" | |
interface ChildProps<T, E = any> { | |
data: T | undefined | |
error: E | undefined | |
isFetching: boolean | |
} | |
type State<T, E> = ChildProps<T, E> | |
function makeGenericEffectReducer<T, E, P>( | |
dispatch: (slice: Partial<State<T, E>>) => void, | |
fetchData: (props: P) => Promise<T>, | |
props: P | |
) { | |
return async () => { | |
dispatch({ isFetching: true }) | |
try { | |
dispatch({ data: await fetchData(props) }) | |
} catch (error) { | |
dispatch({ error }) | |
} finally { | |
dispatch({ isFetching: false }) | |
} | |
} | |
} | |
export default function makeContainerComponent<P, T, E = any>( | |
fetchData: (props: P) => Promise<T>, | |
initialData?: T, | |
...propKeys: (keyof P)[] | |
) { | |
return (ComponentType: React.ComponentType<Partial<ChildProps<T, E>>>) => | |
function GenericContainerComponent(props: P) { | |
const initialState: ChildProps<T, E> = { | |
isFetching: false, | |
error: undefined, | |
data: initialData | |
} | |
const [state, dispatch] = React.useReducer( | |
(state, slice) => ({ ...state, ...slice }), | |
initialState | |
) | |
React.useEffect( | |
makeGenericEffectReducer(dispatch, fetchData, props), | |
propKeys.length > 0 ? propKeys.map(key => props[key]) : undefined | |
) | |
return ( | |
<ComponentType | |
isFetching={state.isFetching} | |
data={state.data} | |
error={state.error} | |
/> | |
) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment