Skip to content

Instantly share code, notes, and snippets.

@busypeoples
Created May 4, 2018 14:42
Show Gist options
  • Save busypeoples/ea1c87c0ee23328dd0344c2d7296d4f9 to your computer and use it in GitHub Desktop.
Save busypeoples/ea1c87c0ee23328dd0344c2d7296d4f9 to your computer and use it in GitHub Desktop.
let str = ReasonReact.string;
let url = "http://localhost:3000/users";
type user = {
id: int,
name: string,
};
type state =
| NotAsked
| Loading
| Failure
| Success(list(user));
module Decode = {
let user = user =>
Json.Decode.{
id: field("id", int, user),
name: field("name", string, user),
};
let users = json : list(user) => Json.Decode.list(user, json);
};
module Encode = {
let user = data => Json.Encode.(object_([("name", string(data.name))]));
};
module User = {
let fetchAll = () =>
Js.Promise.(
Fetch.fetch(url)
|> then_(Fetch.Response.json)
|> then_(json =>
json |> Decode.users |> (users => Some(users) |> resolve)
)
|> catch(_err => resolve(None))
);
let update = ({id, name}) =>
Js.Promise.(
Fetch.fetchWithInit(
url ++ "/" ++ string_of_int(id),
Fetch.RequestInit.make(
~method_=Put,
~body=
Fetch.BodyInit.make(Js.Json.stringify(Encode.user({id, name}))),
~headers=
Fetch.HeadersInit.makeWithArray([|
("content-Type", "application/json"),
|]),
(),
),
)
|> then_(Fetch.Response.json)
|> then_(json =>
json |> Decode.user |> (user => Some(user) |> resolve)
)
|> catch(_err => resolve(None))
);
};
let updateUser = ({id, name}, users) =>
List.map(user => user.id == id ? {...user, name} : user, users);
type action =
| LoadUsers
| LoadedUsers(list(user))
| LoadUsersFailed
| UpdateUser(user);
let component = ReasonReact.reducerComponent("FetchComponent");
let make = _children => {
...component,
initialState: () => NotAsked,
reducer: (action, state) =>
switch (action) {
| LoadUsers =>
ReasonReact.UpdateWithSideEffects(
Loading,
(
self =>
Js.Promise.(
User.fetchAll()
|> then_(result =>
switch (result) {
| Some(users) => resolve(self.send(LoadedUsers(users)))
| None => resolve(self.send(LoadUsersFailed))
}
)
|> ignore
)
),
)
| LoadedUsers(users) => ReasonReact.Update(Success(users))
| LoadUsersFailed => ReasonReact.Update(Failure)
| UpdateUser(user) =>
ReasonReact.UpdateWithSideEffects(
Loading,
(
self =>
Js.Promise.(
User.update(user)
|> then_(result =>
switch (result, state) {
| (Some(u), Success(users)) =>
resolve(self.send(LoadedUsers(updateUser(u, users))))
| (Some(u), _) => resolve(self.send(LoadedUsers([u])))
| (None, _) => resolve(self.send(LoadUsersFailed))
}
)
|> ignore
)
),
)
},
render: self =>
switch (self.state) {
| NotAsked =>
<div>
(str("Click to start load Users"))
<button onClick=(_event => self.send(LoadUsers))>
(str("Load Users"))
</button>
</div>
| Loading => <div> (str("Loading...")) </div>
| Failure => <div> (str("Something went wrong!")) </div>
| Success(users) =>
<div>
<h2> (str("Users")) </h2>
<ul>
(
users
|> List.map(user =>
<li key=(string_of_int(user.id))>
(str(user.name))
<button
onClick=(
_event =>
self.send(
UpdateUser({...user, name: user.name ++ "!"}),
)
)>
(str("Update User"))
</button>
</li>
)
|> Array.of_list
|> ReasonReact.array
)
</ul>
</div>
},
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment