Fable coupled with Fable.React and Fable.Elmish.React are powerful tools to generate javascript applications. But generating good and fast React code is an already complex task that isn’t made simpler by using a different language and a transpiler.

In this series of posts I plan to show how some common React constructs are done in F# and what to look for when optimizing them.

The posts will be:

Starting a sample Fable React project

If you want to try the code for yourself you’ll need a sample

Start with the fable template as in the minimal template

Run it in watch mode with npm start and connect to it via http://localhost:8080/

and connect to it via http://localhost:8080/ Replace the div tag in public/index.html with <div id="root"></div>

tag in with Change the App.fs file to look like that:

module App open Fable . Core open Fable . Core . JsInterop open Fable . Import open Fable . Import . Browser open Fable . Import . React open Fable . Helpers . React open Fable . Helpers . React . Props // -- [BEGIN] part to replace let init () = let element = str "Hello 🌍" ReactDom . render ( element , document . getElementById ( "root" )) // -- [END] part to replace init ()

Creating HTML elements

As F# doesn’t have any JSX-like transform creating React elements is done as explained in the React Without JSX article, except that instead of directly using createElement a bunch of helpers are available in the Fable.Helpers.React module.

For HTML elements the resulting syntax is strongly inspired by the Elm one.

Here is a small sample of the more common ones :

let init () = let element = // Each HTML element has an helper with the same name ul // The first parameter is the properties of the elements. // For html elements they are specified as a list and for custom // elements it's more typical to find a record creation [ ClassName "my-ul" ; Id "unique-ul" ] // The second parameter is the list of children [ // str is the helper for exposing a string to React as an element li [] [ str "Hello 🌍" ] // Helpers exists also for other primitive types li [] [ str "The answer is: " ; ofInt 42 ] li [] [ str "π=" ; ofFloat 3 . 14 ] // ofOption can be used to return either null or something li [] [ str "🤐" ; ofOption ( Some ( str "🔫" )) ] // And it can also be used to unconditionally return null, rendering nothing li [] [ str "😃" ; ofOption None ] // ofList allows to expose a list to react, as with any list of elements // in React each need an unique and stable key [ 1 ; 2 ; 3 ] |> List . map ( fun i -> let si = i . ToString () li [ Key si ] [ str "🎯 " ; str si ]) |> ofList // fragment is the <Fragment/> element introduced in React 16 to return // multiple elements [ 1 ; 2 ; 3 ] |> List . map ( fun i -> let si = i . ToString () li [] [ str "🎲 " ; str si ]) |> fragment [] ] ReactDom . render ( element , document . getElementById ( "root" ))

React components

While it is possible to use React as a templating engine for HTML by using only built-in components, what really unlocks the power of React and where lies the biggest potential for optimization is in its user-defined components.

Creating Components in F# is really similar to how they are created in modern JavaScript. The main difference comes when consuming them as we’ll use the ofType and ofFunction helpers (Instead of using JSX or React.createElement ).

Functional Components

The easiest to use F# components are Functional ones, they don’t need a class, a simple function taking props and returning a ReactElement will do. They can then be created using the ofType helper.

Let’s see how they are created in JavaScript:

function Welcome ( props ) { return < h1 > Hello, { props . name } </ h1 >; } function init () { const element = < Welcome name= "🌍" />; ReactDOM . render ( element , document . getElementById ( "root" )); }

And the equivalent in F#:

type WelcomeProps = { name : string } let Welcome { name = name } = h1 [] [ str "Hello, " ; str name ] let inline welcome name = ofFunction Welcome { name = name } [] let init () = let element = welcome "🌍" ReactDom . render ( element , document . getElementById ( "root" ))

Some notes:

We had to declare WelcomeProps while JavaScript could do without

while JavaScript could do without Using sprintf in the F# sample could have seemed natural but using React for it is a lot better on a performance standpoint as we’ll see later.

Note: Due to some peculiarities of the Fable transform there can be negative performance impact of using them but they are avoidable if you know what to look for. I’ll detail this some more in the second post

Class Components

To create an user-defined component in F# a class must be created that inherit from Fable.React.Component<'props,'state> and implement at least the mandatory render() method that returns a ReactElement .

Let’s port our “Hello World” Component:

type WelcomeProps = { name : string } type Welcome ( initialProps ) = inherit Component < WelcomeProps , obj >( initialProps ) override this . render () = h1 [] [ str "Hello " ; str this . props . name ] let inline welcome name = ofType < Welcome ,_,_> { name = name } [] let init () = let element = welcome "🌍" ReactDom . render ( element , document . getElementById ( "root" ))

Nothing special here, the only gotcha is that the props passed in the primary constructor even though they are in scope in the render() method should not be used.

Class Component with state

All features of React are available in Fable and while the more “Functional” approach of re-rendering with new props is more natural using mutable state is totally possible :

// A pure, stateless component that will simply display the counter type CounterDisplayProps = { counter : int } type CounterDisplay ( initialProps ) = inherit PureStatelessComponent < CounterDisplayProps >( initialProps ) override this . render () = div [] [ str "Counter = " ; ofInt this . props . counter ] let inline counterDisplay p = ofType < CounterDisplay ,_,_> p [] // Another pure component displaying the buttons type AddRemoveProps = { add : MouseEvent -> unit ; remove : MouseEvent -> unit } type AddRemove ( initialProps ) = inherit PureStatelessComponent < AddRemoveProps >( initialProps ) override this . render () = div [] [ button [ OnClick this . props . add ] [ str "👍" ] button [ OnClick this . props . remove ] [ str "👎" ] ] let inline addRemove props = ofType < AddRemove ,_,_> props [] // The counter itself using state to keep the count type CounterState = { counter : int } type Counter ( initialProps ) as this = inherit Component < obj , CounterState >( initialProps ) do this . setInitState ({ counter = 0 }) // This is the equivalent of doing `this.add = this.add.bind(this)` // in javascript (Except for the fact that we can't reuse the name) let add = this . Add let remove = this . Remove member this . Add (_: MouseEvent ) = this . setState ({ counter = this . state . counter + 1 }) member this . Remove (_: MouseEvent ) = this . setState ({ counter = this . state . counter - 1 }) override this . render () = div [] [ counterDisplay { CounterDisplayProps . counter = this . state . counter } addRemove { add = add ; remove = remove } ] let inline counter props = ofType < Counter ,_,_> props [] // createEmpty is used to emit '{}' in javascript, an empty object let init () = let element = counter createEmpty ReactDom . render ( element , document . getElementById ( "root" ))

Note: This sample uses a few react-friendly optimizations that will be the subject of the second post.

That’s all folks

Nothing special this time and for anyone that know both React and Fable there was not a lot of new information but we’ll expand it next time !