Skip to content

Instantly share code, notes, and snippets.

@fernandocamargo
Last active July 26, 2021 23:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fernandocamargo/688145cc5329f7c5f2928ebe0a659d24 to your computer and use it in GitHub Desktop.
Save fernandocamargo/688145cc5329f7c5f2928ebe0a659d24 to your computer and use it in GitHub Desktop.
import { useCallback, useEffect, useRef, useState } from 'react'
import { attempt, fail, getInitialState, succeed } from './reducers'
import { Validity } from './helpers'
export default ({ promise }) => {
const { current: controller } = useRef(new AbortController())
const [state, setState] = useState(getInitialState())
const resolve = useCallback(
(...params) => {
const { check, expire } = new Validity()
const abort = () => controller.abort()
new Promise((resolve, reject) =>
check(promise(...params))
.then((data) => {
setState(succeed(data))
return resolve(data)
})
.catch((error) => {
setState(fail(error))
return reject(error)
})
.finally(() => controller.signal.removeEventListener('abort', expire))
)
controller.signal.addEventListener('abort', expire)
setState(attempt({ params }))
return abort
},
[promise, controller]
)
useEffect(() => () => controller.abort(), [controller])
return { ...state, resolve }
}
import noop from 'lodash/noop'
export const PENDING = new Promise(noop)
import { PENDING } from './constants'
export class Validity {
constructor() {
this.stale = false
}
expire = () => {
this.stale = true
}
succeed = (...params) => (!this.stale ? Promise.resolve(...params) : PENDING)
fail = (...params) => (!this.stale ? Promise.reject(...params) : PENDING)
check = (promise) => {
const { succeed, fail } = this
return promise.then(succeed).catch(fail)
}
}
export const getInitialState = () => ({
loading: false,
data: null,
error: null,
})
export const attempt = () => () => ({ loading: true, data: null, error: null })
export const succeed = (data) => () => ({ loading: false, error: null, data })
export const fail = (error) => () => ({ loading: false, data: null, error })
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment