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.
Follow the Elmish basic instructions to build your program in F#.
let myProgram = Program.mkProgram init update view
open Fable.Elmish.ElmishToReact
let MyProgramComponent = elmishToReactSimple myProgram
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);
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)
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
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
npm install --save-dev elmish-to-react
dotnet add reference ./node_modules/elmish-to-react/Fable.Elmish.ElmishToReact.fsproj
dotnet restore
paket add nuget Fable.Elmish.ElmishToReact -i