Skip to content

Instantly share code, notes, and snippets.

@aspnetde
Last active February 13, 2022 21:33
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save aspnetde/0e7b71bd7108ee62dac4d2783653c141 to your computer and use it in GitHub Desktop.
Save aspnetde/0e7b71bd7108ee62dac4d2783653c141 to your computer and use it in GitHub Desktop.
Feliz – MVU with React Function Components
module App
open Elmish
type State =
{ CurrentUser: string option }
type Msg =
| SignIn of string
| SignOut
let init() = { CurrentUser = None }, Cmd.none
let update (msg: Msg) (state: State) =
match msg with
| SignIn user -> { state with CurrentUser = Some (user) }, Cmd.none
| SignOut -> { state with CurrentUser = None }, Cmd.none
let render (state: State) (dispatch: Msg -> unit) =
match state.CurrentUser with
| Some -> Dashboard.dashboard { User = state.CurrentUser.Value; SignOut = fun () -> SignOut |> dispatch }
| None -> Login.login { SignIn = fun user -> SignIn(user) |> dispatch }
module Dashboard
open Elmish
open Feliz.UseElmish
open Feliz
type State =
{ User: string }
type Props =
{ User: string
SignOut: unit -> unit }
type Msg = | SignOut
let init props =
{ User = props.User }, Cmd.none
let update props msg state =
match msg with
| SignOut -> state, Cmd.ofSub (fun _ -> props.SignOut())
let dashboard = React.functionComponent("Dashboard", fun props ->
let state, dispatch = React.useElmish(init props, update props, [||])
Html.div [
Html.h1 (sprintf "Hi, %s!" state.User)
Html.hr []
Html.button [
prop.text "Sign out"
prop.onClick (fun _ -> SignOut |> dispatch)
]
]
)
module Login
open Feliz
open Feliz.UseElmish
open Elmish
open System
type State =
{ UserName: string
Password: string }
type Props =
{ SignIn: string -> unit }
type Msg =
| SetUserName of string
| SetPassword of string
| SignIn
let init() = { UserName = ""; Password = "" }, Cmd.none
let update props msg state =
match msg with
| SetUserName userName -> { state with UserName = userName }, Cmd.none
| SetPassword password -> { state with Password = password }, Cmd.none
| SignIn -> state, Cmd.ofSub (fun _ -> props.SignIn(state.UserName))
let login = React.functionComponent("LoginForm", fun props ->
let state, dispatch = React.useElmish(init, update props, [||])
let signInPossible =
(not (String.IsNullOrWhiteSpace(state.UserName))) &&
(not (String.IsNullOrWhiteSpace(state.Password)))
Html.div [
Html.label [ prop.text "User name"; prop.htmlFor "user" ]
Html.br []
Html.input [
prop.id "user"
prop.type'.text
prop.onChange (SetUserName >> dispatch)
]
Html.br []
Html.label [ prop.text "Password"; prop.htmlFor "password" ]
Html.br []
Html.input [
prop.id "password"
prop.type'.password
prop.onChange (SetPassword >> dispatch)
]
Html.br []
Html.br []
Html.button [
prop.onClick (fun _ -> SignIn |> dispatch)
prop.text "Sign in"
prop.disabled (not signInPossible)
]
]
)
@aspnetde
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment