Skip to content

Instantly share code, notes, and snippets.

@jcuffe
Created February 2, 2020 22:03
Show Gist options
  • Save jcuffe/882de6d48d9e419c85787c843672edab to your computer and use it in GitHub Desktop.
Save jcuffe/882de6d48d9e419c85787c843672edab to your computer and use it in GitHub Desktop.
Suspense integration for HelloRevel Redux
const App = () => (
<ErrorBoundary>
<Suspense fallback={LoadingPage}>
// ...routes
</Suspense>
</ErrorBoundary>
)
const Detail = () => {
const { id } = useMatch()
const event = useResource("events", id, fetchEvent)
return (
// `event` is guaranteed to be defined here
)
}
export const fetcher = (key, dispatch) => {
const config = {
...
}
// Make the request
const promise = axios(config)
.then(data => dispatch(updateReducer(data))
.catch(err => dispatch(updateReducer(err))
// Store the promise on state for the fetcher
dispatch(updateReducer(promise))
}
export const useResource(name, key, fetcher, fetcherArgs) {
// Look for value on top level reducer
const value = useSelector(state => state[name][key])
const dispatch = useDispatch()
switch(getState(value)) {
// If the value on state is a promise, we're waiting for a fetch
// Throw the promise for Suspense
case PENDING:
// If the value is an error, our fetch failed
// Throw an error for the ErrorBoundary
case FAILURE:
throw value
// We have our data!
case SUCCESS:
return value
// This is the first access attempt (or something cleared the value)
// Kick off a fetch
default:
fetcher(key, ...fetcherArgs, dispatch)
}
}
getState(value) {
const states = {
PENDING: isPromise,
FAILURE: isError,
SUCCESS: isValue
}
for (let key in states) {
if (states[key](value)) {
return states[key]
}
}
}
isValue = value => !isPromise(value) && isDefined(value) && !isError(value)
isPromise = value => value && typeof value.then == "function"
isUndefined = value => value === undefined
isError = value => value instanceof Error
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment