Created
June 25, 2020 18:15
-
-
Save JordanMarr/29ed7bfd1737dd38eab9eeeae070e6f4 to your computer and use it in GitHub Desktop.
Fable.React: Updating a parent context from a child component
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
module Contexts | |
open Feliz | |
open Elmish.Toastr | |
open Elmish | |
open Domain.Auth | |
type ToastMessage = | |
| InfoMsg of string | |
| SuccessMsg of string | |
| ErrorMsg of string | |
type AppState = { | |
User: Domain.Auth.User | |
Toast: ToastMessage -> unit | |
} | |
let private init = | |
{ User = { User.ClientId = ""; FirstName = ""; LastName = ""; Username = "" } | |
Toast = fun msg -> () } | |
let appContext = React.createContext<AppState>(name = "UserContext", defaultValue = init) |
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
module App | |
open Elmish | |
open Feliz | |
open Feliz.Router | |
open Fable.React | |
open Fable.React.Props | |
open Domain.Auth | |
open Elmish.Toastr | |
open Contexts | |
type State = { | |
CurrentUrl: string list | |
IsAuthenticating: bool | |
User: User option | |
} | |
type Msg = | |
| UrlChanged of string list | |
| GetUserResponse of Result<UserStatus, string> | |
| Toast of Cmd<Msg> | |
let init() = | |
{ CurrentUrl = []; IsAuthenticating = true; User = None }, Cmd.OfPromise.perform HttpService.getUser () GetUserResponse | |
let update msg state = | |
match msg with | |
| UrlChanged segments -> { state with CurrentUrl = segments }, Cmd.none | |
| GetUserResponse userResult -> | |
match userResult with | |
| Ok userStatus -> | |
match userStatus with | |
| Authenticated user -> { state with User = Some user; IsAuthenticating = false }, Cmd.none | |
| Unauthenticated -> { state with User = None; IsAuthenticating = false }, Cmd.none | |
| Error err -> { state with User = None; IsAuthenticating = false }, Cmd.none | |
| Toast toastCmd -> | |
state, toastCmd | |
let render state dispatch = | |
let content = | |
match state.CurrentUrl with | |
| [ ] | |
| [ "home" ] -> HomePage.page() | |
// ... | |
| _ -> Html.h1 "Not found" | |
let content = | |
match state.User with | |
| Some user -> | |
content | |
| None -> | |
if state.IsAuthenticating then | |
h4 [] [ str "Authenticating..." ] | |
else | |
// Autodesk Login | |
a [Href "/signin"] [ | |
button [Class "btn btn-lg btn-default"; Id "autodeskSigninButton"] [ | |
img [Src "https://github.com/Autodesk-Forge/learn.forge.viewhubmodels/raw/master/img/autodesk_text.png"; Style [Height "20"]] | |
div [] [str "Sign in"] | |
] | |
] | |
let toast (tm: ToastMessage) = | |
let toastCmd = | |
match tm with | |
| InfoMsg msg -> Toastr.message msg |> Toastr.info | |
| SuccessMsg msg -> Toastr.message msg |> Toastr.success | |
| ErrorMsg msg -> Toastr.message msg |> Toastr.error | |
dispatch (Toast toastCmd) | |
let pageWithUserContext = | |
match state.User with | |
| Some user -> | |
React.contextProvider(Contexts.appContext, { AppState.User = user; AppState.Toast = toast }, | |
Layout.layout {| Content = content; User = state.User; CurrentUrl = state.CurrentUrl |} | |
) | |
| None -> | |
Layout.layout {| Content = content; User = state.User; CurrentUrl = state.CurrentUrl |} | |
Router.router [ | |
Router.onUrlChanged (UrlChanged >> dispatch) | |
Router.application pageWithUserContext | |
] |
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
/// A very simple page that updates App level context (uses useState instead of useReducer or useElmish) | |
module JobEditPage | |
open Feliz | |
open Fable.React | |
open Fable.React.Props | |
open Contexts | |
/// Displays the backup job edit page. | |
let page = React.functionComponent(fun (props: {| Id: string option |}) -> | |
let job, setJob = React.useState(blankJob) | |
let ctx = React.useContext(Contexts.appContext) | |
// ... | |
let save() = | |
promise { | |
match! HttpService.saveJob job with | |
| Ok job -> | |
setJob job | |
ctx.Toast (SuccessMsg "The backup job was saved.") | |
| Error err -> | |
ctx.Toast (ErrorMsg err) | |
} | |
|> ignore | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment