Skip to content

Instantly share code, notes, and snippets.

@tom-sherman
Created June 12, 2022 08:38
Show Gist options
  • Save tom-sherman/b9624d5129c9971ed265382021857cf8 to your computer and use it in GitHub Desktop.
Save tom-sherman/b9624d5129c9971ed265382021857cf8 to your computer and use it in GitHub Desktop.
WIP - use-effect-reducer in ReScript
type effect
@module("use-effect-reducer")
external useEffectReducer: (
@uncurry (
'state,
'action,
@uncurry ((('state, unit, @uncurry ('action => unit)) => option<unit => unit>) => effect),
) => 'state,
'state,
) => ('state, 'action => unit) = "useEffectReducer"
let fetchRandomDog = () =>
Promise.make((res, rej) => {
Js.Global.setTimeout(() => {
let fail = Js.Math.random() < 0.1
if fail {
rej(. Js.Exn.anyToExnInternal("Failed"))
} else {
Webapi.Fetch.fetch("")
->Promise.then(Webapi.Fetch.Response.json)
->Promise.thenResolve(data => res(. data))
->Promise.catch(err => {
rej(. err)
Promise.resolve()
})
->ignore
}
}, 1000)->ignore
})
type event = Fetch | Resolve(Js.Json.t) | Reject(exn) | Cancel
type stateValue = Idle | Success(Js.Json.t) | Failure | Loading
type state = {promise: option<effect>, value: stateValue}
let dogReducer = (state, event, exec) =>
switch state.value {
| Idle
| Success(_)
| Failure =>
switch event {
| Fetch => {
value: Loading,
promise: Some(
exec((_, _, dispatch) => {
let canceled = ref(false)
fetchRandomDog()
->Promise.thenResolve(data => {
if !canceled.contents {
dispatch(Resolve(data))
}
()
})
->Promise.catch(error => {
if !canceled.contents {
dispatch(Reject(error))
}
Promise.resolve()
})
->ignore
Some(() => canceled := true)
}),
),
}
| _ => state
}
| Loading =>
switch event {
| Resolve(data) => {
promise: state.promise,
value: Success(data),
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment