ch 5

Fable & Elmish

What is Fable ?

  • Fable is an F#-to-JavaScript (JS) compiler.
  • Fable brings all the power of F# to the JS ecosystem.
  • Use JS libraries from F# (and vice versa) as well as make use of standard JS tools.

https://safe-stack.github.io/docs/component-fable/

Benefis of Fable

  • Static type
  • All of F#'s features
  • Runs on JavaScript
  • Great interoperability with JavaScript libraries

How to use Fable?

Use npm package

https://fable.io/docs/2-steps/your-first-fable-project.html

practice: fable

Not enough

https://fable.io/docs/communicate/js-from-fable.html

React

what is React?

React is a free and open-source front-end JavaScript library for building user interfaces based on UI components. by wiki

features

  • Declarative
  • Component-Based
  • Learn Once, Write Anywhere

F# React wrappers

Femto

Femto is CLI tool that manages the npm packages used by Fable bindings. It installs them using the npm package manager that you are using whether that is npm (default)

Fable Packages

Fable.Elmish.React (nuget)
  |
  | -- Fable.Elmish (nuget)
  | -- Fable.React (nuget)
        |
        | -- react@16.8.0 (npm)
        | -- react-dom@16.8.0 (npm)

Feliz

A fresh retake of the base React DSL to build React applications, optimized for happiness.

Here is how it looks like:

module App

open Feliz

[<ReactComponent>]
let Counter() =
    let (count, setCount) = React.useState(0)
    Html.div [
        Html.button [
            prop.style [ style.marginRight 5 ]
            prop.onClick (fun _ -> setCount(count + 1))
            prop.text "Increment"
        ]

        Html.button [
            prop.style [ style.marginLeft 5 ]
            prop.onClick (fun _ -> setCount(count - 1))
            prop.text "Decrement"
        ]

        Html.h1 count
    ]

open Browser.Dom

ReactDOM.render(Counter(), document.getElementById "root")

practice: Wrapping a React component

Elmish

Elmish is a library for building single page applications in F# applications, following the model-view-update(MVU) architecture made famous by Elm

MVU architeture

practice: Elmish - counter

Elmish on SAFE Template

let update (msg: Msg) (model: Model) : Model * Cmd<Msg> =
    match msg with
    | GotTodos todos -> { model with Todos = todos }, Cmd.none
    | SetInput value -> { model with Input = value }, Cmd.none
    | AddTodo ->
        let todo = Todo.create model.Input

        let cmd =
            Cmd.OfAsync.perform todosApi.addTodo todo AddedTodo

        { model with Input = "" }, cmd
    | AddedTodo todo ->
        { model with
              Todos = model.Todos @ [ todo ] },
        Cmd.none

How to write View?

  1. Fable.React
  2. Feliz
  3. Feliz.Bulma

Fable.React

  div []
      [ button [ OnClick (fun _ -> dispatch Increment) ] [ str "+" ]
        div [] [ str (string model) ]
        button [ OnClick (fun _ -> dispatch Decrement) ] [ str "-" ] ]

https://mangelmaxime.github.io/html-to-elmish/

Feliz

Html.div [
    prop.className "columns"
    prop.children [
        Html.div [
            prop.className "column is-2"
            prop.children [
                Html.button.a [
                    prop.className "button"
                    prop.text "Click me"
                ]
            ]
        ]
    ]
]

Feliz.Bulma

open Feliz.Bulma

Bulma.columns [
    Bulma.column [
        column.is2 // <-- note context helper here
        prop.children [
            Bulma.button.button "Click me"
        ]
    ]
]

Difference

My journey with Feliz | A comparison between Fable.React and Feliz #155

References

https://reactjs.org/

F# wrappers for React components

Feliz.Bulma

return to Outline