React extensions for Elmish apps

Elmish-React implements boilerplate to wire up the rendering of React and React Native components and several rendering optimization functions.


paket add nuget Fable.Elmish.React

You also need to install React:

yarn add react react-dom

Program module extensions

Both React and React Native applications need a root component to be rendered at the specified placeholder, see browser and native tutorials for details.

Lazy views

By default, every time the main update function is called (upon receiving and processing a message), the entire DOM is constructed anew and passed to React for reconciliation. If there are no changes in the model of some component, its view function will under normal circumstances not return a different result. React will then still perform reconciliation and realize that there is no need to update the component's UI. Consequently, when the DOM is sufficiently large or its construction extremely time-consuming, this unnecessary work may have noticeable repercussions in terms of application performance. Thanks to lazy views however, the update process can be optimized by avoiding DOM reconciliation and construction steps, but only if the model remains unchanged.

lazyView can be used with equatable models (most F# core types: records, tuples, etc).

lazyViewWith can be used with types that don't implement the equality constraint (such as types/instances coming from JS libraries) by passing the custom equal function that compares the previous and the new model.

These functions work for both React and React Native views. They are used in the following way.

Given a view function of one argument:

open Elmish.React

// val view : 'a -> ReactElement
lazyView view1 model

// or given a typical view function, defined like this:
// val view : 'a -> Dispatch<'msg> -> ReactElement
lazyView2 view2 model dispatch

the rendered view will be cached for as long as model remains the same.

Given a view function of three arguments:

// val view : 'a -> 'b -> Dispatch<'msg> -> ReactElement
lazyView3 view3 model1 model2 dispatch

Elmish-React will skip calling the view3 for as long as both model1 and model2 remain unmodified.

val view1 : model:'a -> Fable.Import.React.ReactElement

Full name: Index.view1
val model : 'a
namespace Fable
namespace Fable.Import
module React

from Fable.Import
type ReactElement

Full name: Fable.Import.React.ReactElement
val failwith : message:string -> 'T

Full name: Microsoft.FSharp.Core.Operators.failwith
val view2 : model:'a -> dispatch:Elmish.Dispatch<'msg> -> Fable.Import.React.ReactElement

Full name: Index.view2
val dispatch : Elmish.Dispatch<'msg>
namespace Elmish
type Dispatch<'msg> = 'msg -> unit

Full name: Elmish.Dispatch<_>
val view3 : model1:'a -> model2:'b -> dispatch:Elmish.Dispatch<'msg> -> Fable.Import.React.ReactElement

Full name: Index.view3
val model1 : 'a
val model2 : 'b
val model : string option

Full name: Index.model
union case Option.Some: Value: 'T -> Option<'T>
val model1 : int option

Full name: Index.model1
val model2 : float option

Full name: Index.model2
val dispatch : Elmish.Dispatch<unit>

Full name: Index.dispatch
type unit = Unit

Full name: Microsoft.FSharp.Core.unit
namespace Elmish.React
val lazyView : view:('model -> Fable.Import.React.ReactElement) -> ('model -> Fable.Import.React.ReactElement) (requires equality)

Full name: Elmish.React.Common.lazyView
val lazyView2 : view:('model -> Elmish.Dispatch<'msg> -> Fable.Import.React.ReactElement) -> ('model -> Elmish.Dispatch<'msg> -> Fable.Import.React.ReactElement) (requires equality)

Full name: Elmish.React.Common.lazyView2
val lazyView3 : view:('a -> 'b -> Elmish.Dispatch<'c> -> Fable.Import.React.ReactElement) -> ('a -> 'b -> Elmish.Dispatch<'c> -> Fable.Import.React.ReactElement) (requires equality and equality)

Full name: Elmish.React.Common.lazyView3