Skip to content

Instantly share code, notes, and snippets.

@johnhaley81
Created July 7, 2020 17:11
Show Gist options
  • Save johnhaley81/972fe8581934ffe0ae3eb9f7620bd9a4 to your computer and use it in GitHub Desktop.
Save johnhaley81/972fe8581934ffe0ae3eb9f7620bd9a4 to your computer and use it in GitHub Desktop.
open Relude.Globals; // I usually do this in bsconfig
type user = {
firstName: string,
lastName: string,
};
type error =
| AlreadyLoggedIn;
type context = {
// User can be Initialized, Loading, Completed with some Result.t or Reloading with some previous Result.t
user: AsyncResult.t(user, ReludeFetch.Error.t(error)),
// These are store in the context but we'll define them statically and pass in the state
login: (string, string, bool) => unit,
logout: unit => unit,
};
// Don't store these in the context, derive them from what the context has
let isLoading =
fun
| {user} => user |> AsyncResult.isBusy; // Returns true if the result is being loaded
let isLoggedIn =
fun
| {user} =>
user
|> AsyncResult.getOk // Returns true if there was ever
|> Option.isSome;
let context =
React.createContext({
user: AsyncResult.init, // This starts as initialized
login: (_username, _password, _someBoolVal) => (), // these are just mocked for right now
logout: () => (),
});
React.useContext(context);
module MyApp = {
// Static function which takes in relevant parts of the context when used
// It will return the IO that contains the value of the user or the error
let login = (currentUser, _username, _password, _someBoolVal) =>
currentUser
|> AsyncResult.getOk
|> Option.fold(
{firstName: "Blue", lastName: "HotDog"} |> IO.pure, _currentUser =>
IO.throw(
ReludeFetch.Error.DecodeError({
url: "none",
innerError: AlreadyLoggedIn,
}),
)
);
[@react.component]
let make = () => {
// The state here controls the values in the context for
let (user, setUser) = React.useState(() => AsyncResult.init);
// We have this function set all of the loading/reloading/value wiring up that we need
let login = (username, password, someBoolVal) =>
IO.suspend(() => setUser(AsyncResult.toBusy))
|> IO.flatMap(() => login(user, username, password, someBoolVal))
|> IO.unsafeRunAsync(result =>
setUser(_prevUser => result |> AsyncData.complete)
);
let logout = () => setUser(_prevUser => AsyncResult.init);
// This is going to be the actual value used in the context.
let value = {user, login, logout};
// We create the provider here that allows the children to plug into the context
let provider = context |> React.Context.provider;
// the <div /> will just be whatever children you want that will have access to the context
provider({"value": value, "children": <div />});
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment