Search code examples
f#fable-f#elmish

Render component in Fable-Elmish


I have set up a standard SAFE application with the dotnet new SAFE command resulting in the two Server and Client projects (and the Shared folder).

The Client project has the Client.fs file with the view function and the bootstrapping code, which is just as the template generates it:

Program.mkProgram init update view
#if DEBUG
|> Program.withConsoleTrace
|> Program.withHMR
#endif
|> Program.withReact "elmish-app"
#if DEBUG
|> Program.withDebugger
#endif
|> Program.run

I have now added a simple component:

type MyComponentProps = {
    data : int
}

type MyComponent(initialProps) =
    inherit Component<MyComponentProps, obj>(initialProps)
    do
      base.setInitState({ data = initialProps.data })

    override this.render() =
        h1 [] [str ("Hello World " + this.props.data.ToString())]

    override this.componentDidMount() =
        // Do something useful here... ;)
        console.log("Component Did Mount!")

But I cannot figure out how to properly instantiate this component in the view function. I really think this ought to work:

let view (model : Model) (dispatch : Msg -> unit) =
    MyComponent({data = 42}) :> ReactElement

But this results in the browser in the - now - dreaded:

Error: Objects are not valid as a React child (found: object with keys {props, context, refs, updater, state}). If you meant to render a collection of children, use an array instead. I really don't get that since the type is ReactElement which should be fine...

Instantiating the component manually and calling render() does sort of work, but of course componentDidMount() is not called:

let myComponent = MyComponent({data = 42})
myComponent.render() 

So: How do I get MyComponent properly instantiated and "injected" into React?


Solution

  • You can use ofType from Fable.Helpers.React

    open Fable.Helpers.React
    let view (model : Model) (dispatch : Msg -> unit) =
        ofType<MyComponent,_,_> { data = 42 } []