Last active
September 19, 2020 17:29
-
-
Save shannonmoeller/c3396911dcfa11cd98b65d37e19719af to your computer and use it in GitHub Desktop.
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 { useAsync } from './use-async.js'; | |
import { useAsyncCallback } from './use-async-callback.js'; | |
export function Cat() { | |
const { data, error, loading } = useAsync( | |
async (signal) => { | |
const cats = await fetch( | |
'https://api.thecatapi.com/v1/images/search?size=full', | |
{ signal } | |
); | |
return cats?.[0]?.url; | |
} | |
); | |
if (loading) { | |
return <p>Loading...</p>; | |
} | |
if (error) { | |
return <p>Unable to load a cat: {error.message}</p>; | |
} | |
if (!data) { | |
return <p>No cat for you.</p>; | |
} | |
return <img src={data} alt="cat" />; | |
} | |
export function ResizeCat() { | |
const [{ data, error, loading }, getCat] = useAsync( | |
(signal) => async (size) => { | |
const cats = await fetch( | |
`https://api.thecatapi.com/v1/images/search?size=${size}`, | |
{ signal } | |
); | |
return cats?.[0]?.url; | |
} | |
); | |
return ( | |
<> | |
<button onClick={() => getCat('small')}>Small</button> | |
<button onClick={() => getCat('med')}>Medium</button> | |
<button onClick={() => getCat('full')}>Full</button> | |
(loading ? ( | |
<p>Loading...</p> | |
) : error ? ( | |
<p>Unable to load a cat: {error.message}</p> | |
) : data ? ( | |
<p>No cat for you.</p> | |
) : ( | |
<img src={data} alt="cat" /> | |
)) | |
</> | |
); | |
} |
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 { useCallback, useState } from 'react'; | |
export function useAsyncCallback(handlerFactory, deps = []) { | |
const [state, setState] = useState({ | |
controller: null, | |
data: null, | |
error: null, | |
loading: false, | |
}); | |
const callback = useCallback( | |
async (...args) => { | |
const controller = new AbortController(); | |
const { signal } = controller; | |
try { | |
setState(prev => { | |
if (prev.controller) { | |
prev.controller.abort(); | |
} | |
return { | |
controller, | |
data: null, | |
error: null, | |
loading: true, | |
}; | |
}); | |
const handler = await handlerFactory(signal); | |
if (signal.aborted) { | |
return; | |
} | |
const result = await handler(...args); | |
if (signal.aborted) { | |
return; | |
} | |
setState(prev => ({ | |
...prev, | |
data: result, | |
error: null, | |
loading: false, | |
})); | |
} catch (err) { | |
if (signal.aborted) { | |
return; | |
} | |
controller.abort(); | |
setState(prev => ({ | |
...prev, | |
data: null, | |
error: err, | |
loading: false, | |
})); | |
} | |
}, | |
deps | |
); | |
return [state, callback]; | |
} |
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 { useEffect, useState } from 'react'; | |
export function useAsync(handler, deps = []) { | |
const [state, setState] = useState({ | |
controller: null, | |
data: null, | |
error: null, | |
loading: true, | |
}); | |
useEffect( | |
() => { | |
const controller = new AbortController(); | |
const { signal } = controller; | |
(async () => { | |
try { | |
setState(prev => { | |
if (prev.controller) { | |
prev.controller.abort(); | |
} | |
return { | |
controller, | |
data: null, | |
error: null, | |
loading: true, | |
}; | |
}); | |
const result = await handler(signal); | |
if (signal.aborted) { | |
return; | |
} | |
setState(prev => ({ | |
...prev, | |
data: result, | |
error: null, | |
loading: false, | |
})); | |
} catch (err) { | |
if (signal.aborted) { | |
return; | |
} | |
controller.abort(); | |
setState(prev => ({ | |
...prev, | |
data: null, | |
error: err, | |
loading: false, | |
})); | |
} | |
})(); | |
return () => { | |
controller.abort(); | |
}; | |
}, | |
deps | |
); | |
return state; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment