Created
July 7, 2020 17:11
-
-
Save johnhaley81/972fe8581934ffe0ae3eb9f7620bd9a4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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