Skip to content

Instantly share code, notes, and snippets.

@broerjuang
Created April 17, 2020 17:22
Show Gist options
  • Save broerjuang/04596aed907e9decebb409d76994e88a to your computer and use it in GitHub Desktop.
Save broerjuang/04596aed907e9decebb409d76994e88a to your computer and use it in GitHub Desktop.
Renata
module AsyncResult = Relude.AsyncResult;
module Effect = ReludeReact.Effect;
module IO = Relude.IO;
module Option = Relude.Option;
module Reducer = ReludeReact.Reducer;
let (toBusy, completeOk, completeError) =
AsyncResult.(toBusy, completeOk, completeError);
type state('a, 'e) = AsyncResult.t('a, 'e);
type action('a, 'e, 't) =
| Mutate('t)
| MutateSucceed('a)
| MutateFailed('e);
type config('a, 'e, 't) = {
onSuccess: option('a => unit),
onError: option('e => unit),
handler: 't => IO.t('a, 'e),
};
let%private void = ();
let reducer = (config, state, action) => {
switch (action) {
| Mutate(t) =>
Reducer.UpdateWithIO(
state |> toBusy,
config.handler(t)
|> IO.bimap(d => MutateSucceed(d), e => MutateFailed(e)),
)
| MutateSucceed(d) =>
UpdateWithSideEffect(
d |> completeOk,
_self => {config.onSuccess |> Option.fold(void, fn => fn(d))},
)
| MutateFailed(e) =>
UpdateWithSideEffect(
e |> completeError,
_self => {config.onError |> Option.fold(void, fn => fn(e))},
)
};
};
let useMutation = (~onSuccess=?, ~onError=?, handler) => {
let (state, send) =
Reducer.useReducer(reducer({onSuccess, handler, onError}), Init);
(state, t => send(Mutate(t)));
};
@broerjuang
Copy link
Author

Fetcher

module AsyncResult = Relude.AsyncResult;
module IO = Relude.IO;
module Reducer = ReludeReact.Reducer;
module Effect = ReludeReact.Effect;

type state('a, 'e) = AsyncResult.t('a, 'e);
type action('a, 'e) =
  | Start
  | Complete('a)
  | CompleteError('e);

let reducer = (cb, state, action) => {
  switch (action) {
  | Start =>
    ReludeReact.Reducer.UpdateWithIO(
      state |> AsyncResult.toBusy,
      cb |> IO.bimap(data => Complete(data), error => CompleteError(error)),
    )
  | Complete(data) => Update(data |> AsyncResult.completeOk)
  | CompleteError(error) => Update(error |> AsyncResult.completeError)
  };
};

let useFetcher = (cb, render) => {
  let (state, send) = Reducer.useReducer(reducer(cb), AsyncResult.init);

  Effect.useOnMount(() => {send(Start)});

  render(state);
};

let let_ = (cb, render) => useFetcher(cb, render);

@mfakhrusy
Copy link

thanks 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment