Skip to content

Instantly share code, notes, and snippets.

@mlms13
Created February 12, 2019 22:42
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mlms13/f4a6e2620cbd3bce315786fc6ed66618 to your computer and use it in GitHub Desktop.
Save mlms13/f4a6e2620cbd3bce315786fc6ed66618 to your computer and use it in GitHub Desktop.
Dealing with async changes to state in ReasonReact
type state = {products: RemoteData.t(array(Product.t), string)};
type action =
| FetchProducts
| SetProducts(RemoteData.t(array(Product.t), string));
let component = ReasonReact.reducerComponent(__MODULE__);
let make = _children => {
...component,
initialState: () => {products: NotAsked},
reducer: (action, state) =>
switch (action) {
| FetchProducts =>
UpdateWithSideEffects(
{...state, products: Loading},
(
({send}) =>
Api.getProducts()
|> Js.Promise.then_(products => {
send(SetProducts(Success(products)));
Js.Promise.resolve(products);
})
|> Js.Promise.catch(err => {
send(SetProducts(Failure("Failed to load products")));
Js.Promise.reject(err);
})
|> ignore
),
)
| SetProducts(data) => Update({...state, products: data})
},
render: ({send, state}) =>
switch (state.products) {
| NotAsked =>
<button onClick=(_ => send(FetchProducts))>
{ReasonReact.string("Load Products")}
</button>
| Loading => <LoadingSpinner />
| Failure(msg) =>
<div className="alert alert-error"> {ReasonReact.string(msg)} </div>
| Success(products) =>
let children = products |> Array.map(product => <Product product />);
<div> ...children </div>;
},
};
/**
* Type inspired by Kris Jenkins' type of the same name in Elm/PS
*/
type t('a, 'e) =
| NotAsked
| Loading
| Success('a)
| Failure('e);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment