Use an async effect

·

–– views

#react#hooks#async#effect

function useAsync(asyncCallback) {

let [state, dispatch] = React.useReducer(asyncReducer)

React.useEffect(() => {

let promise = asyncCallback()

if (!promise) return

dispatch({ type: 'pending' })

promise

.then((data) => dispatch({ type: 'resolved', data }))

.catch((error) => dispatch({ type: 'rejected', error }))

}, [asyncCallback])

return state

}

function Component({ input }) {

// Remember to wrap the async job in a useCallback

let asyncCallback = React.useCallback(() => {

if (!input) return

// Run the async effect (fetch is an example)

return fetch(input)

}, [input])

let { status, data, error } = useAsync(asyncCallback)

switch (status) {

case 'idle':

return 'Waiting for the async to trigger'

case 'pending':

return 'Pending UI'

case 'rejected':

throw error

case 'resolved':

return 'Data UI'

default:

throw new Error('This should be impossible')

}

}

How to clean the side effect (the async job start but then the component unmounted) ? - useSafeDispatch !

function useAsync(asyncCallback) {

let [state, unsafeDispatch] = React.useReducer(asyncReducer)

let dispatch = useSafeDispatch(unsafeDispatch)

React.useEffect(() => {

let promise = asyncCallback()

if (!promise) return

dispatch({ type: 'pending' })

promise

.then((data) => dispatch({ type: 'resolved', data }))

.catch((error) => dispatch({ type: 'rejected', error }))

}, [asyncCallback])

return state

}