Skip to content
Wrap an Elmish program as a React component
F# JavaScript HTML
Branch: master
Clone or download
Ian Streeter
Latest commit 9514bb1 Sep 2, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.paket Start of elmishToReact Aug 13, 2019
example Add a nuspec in case we publish to nuget Aug 26, 2019
.gitignore Better structure for a npmjs package Aug 22, 2019
ElmishToReact.fs Add a nuspec in case we publish to nuget Aug 26, 2019
Fable.Elmish.ElmishToReact.fsproj Release npm version 0.0.1 Sep 2, 2019
LICENSE Create LICENSE Sep 2, 2019
README.md Add a nuspec in case we publish to nuget Aug 26, 2019
package.json Release npm version 0.0.1 Sep 2, 2019
paket.dependencies
paket.lock Start of elmishToReact Aug 13, 2019
paket.references Start of elmishToReact Aug 13, 2019
yarn.lock Better structure for a npmjs package Aug 22, 2019

README.md

elmish-to-react

Wrap an Elmish program as a React component.

This is helpful when writing a React app that needs to render an Elmish program as a reuseable component.

A basic example

Step 1: Write a Elmish program in F#

Follow the Elmish basic instructions to build your program in F#.

let myProgram = Program.mkProgram init update view

Step 2: Wrap your program into a React component

open Fable.Elmish.ElmishToReact
let MyProgramComponent = elmishToReactSimple myProgram

Step 3: Start using your component

From your javascript/react code you can render your wrapped program just like any regular React component:

const WrapperComponent = (props) =>
  <div>
    <p>Here's the wrapped program:</p>
    <MyProgramComponent/>
  </div>

ReactDOM.render(<WrapperComponent/>, element);

Passing Props

In React we like to pass props into child components. The child should re-render when there is a change in the props it receives from the parent.

How can we pass in props to our Elmish program and trigger a re-render?

Let's rewrite our program so it is ready to receive props. The props includes a label string and a saySomething function is used to pass information from the child back up the parent.

type Props =
  abstract label : string
  abstract saySomething : string -> unit

type Model =
  { Props : Props
    // ...plus any other model attributes you need
  }

type Msg =
  | UpdateProps of Props
  // ...plus any other Msg types you need

let init props =
  { Props = props }, Cmd.none

let update msg model =
  match msg with
  | UpdateProps props ->
      { model with Props = props }, Cmd.none

let program = Program.mkProgram init update view

Next we "externalise" our program. This allows us to externally feed a props message into the Elmish program:

open Fable.Elmish.ElmishToReact

let externalisedProgram =
  Externalised.externalise program
  |> Externalised.withPropsMsg UpdateProps

let MyProgramComponent = elmishToReact externalisedProgram

In our javascript code we can pass the props into our wrapped program:

ReactDom.render(
    <MyProgramComponent label="Hello, world"
                        saySomething={(msg) => console.log(msg)}/>,
  element)

Unmounting

React might need to repeatedly mount and unmount the Elmish program as the user navigates around a single page app. The Elmish program might want to clean-up its resources each time it is unmounted.

Let's rewrite our program so it can receive an unmount message:

type Msg =
  | Unmount
  // ...plus any other Msg types you need

let update msg model =
  match msg with
  | Unmount ->
      // Do any clean-up here
      model, Cmd.none

let program = Program.mkProgram init update view

Next we add the Unmount message to our externalised program.

open Fable.Elmish.ElmishToReact

let externalisedProgram =
  Externalised.externalise program
  |> Externalised.withUnmountMsg Unmount

let MyProgramComponent = ElmishComponent.elmishToReact externalisedProgram

A complete example

Example.fs contains a example of an Elmish program demonstrating all the features described above.

example.js is an example of calling the elmish program with react syntax.

To run the example....

yarn run start

...and open http://localhost:8080 in your web browser

Installation with npm

npm install --save-dev elmish-to-react
dotnet add reference ./node_modules/elmish-to-react/Fable.Elmish.ElmishToReact.fsproj
dotnet restore

Installation with paket

paket add nuget Fable.Elmish.ElmishToReact -i
You can’t perform that action at this time.