fable-compiler / fable-react

Fable bindings and helpers for React and React Native
MIT License
273 stars 67 forks source link

How to instantiate a custom React Component in Fable? #209

Closed Montana closed 3 years ago

Montana commented 3 years ago

I am trying to write a simple React component using Fable. It should take display a simple counter with + and - buttons. It also takes a message string via props. All my dispatchers are working.

What is unexpected is that the code compiles, but it throws a run-time error:

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.

Here is the code:

module App

open Fable.Core
open Fable.Core.JsInterop
open Fable.React
open Browser
open Browser.Types

type App (message) =
  inherit Component<string, int> (message) with

    do
      base.setInitState(0)

    override this.render () =
      div
        []
        [
          h1 [] [ str (sprintf "%s - %i" this.props this.state) ]
          button [ Props.OnClick (fun _ -> this.setState (fun s _ -> s + 1)) ] [ str "+" ]
          button [ Props.OnClick (fun _ -> this.setState (fun s _ -> s - 1)) ] [ str "-" ]
        ]

let render () =
  ReactDom.render(
    App "Counter",
    document.getElementById "root")

render ()

My paket.lock:

STORAGE: NONE
RESTRICTION: || (== netcoreapp3.1) (== netstandard2.0) (== netstandard2.1)
NUGET
  remote: https://api.nuget.org/v3/index.json
    Fable.Browser.Blob (1.1)
      Fable.Core (>= 3.0)
      FSharp.Core (>= 4.6.2)
    Fable.Browser.Dom (1.1)
      Fable.Browser.Blob (>= 1.1)
      Fable.Browser.Event (>= 1.0)
      Fable.Browser.WebStorage (>= 1.0)
      Fable.Core (>= 3.0)
      FSharp.Core (>= 4.6.2)
    Fable.Browser.Event (1.0)
      Fable.Core (>= 3.0)
      FSharp.Core (>= 4.5.2)
    Fable.Browser.WebStorage (1.0)
      Fable.Browser.Event (>= 1.0)
      Fable.Core (>= 3.0)
      FSharp.Core (>= 4.5.2)
    Fable.Core (3.1.5)
      FSharp.Core (>= 4.7)
    Fable.React (5.3.6)
      Fable.Browser.Dom (>= 1.0)
      Fable.Core (>= 3.0)
      FSharp.Core (>= 4.7)
    FSharp.Core (4.7)`

Note: I want to use setState (rather than hooks or Elmish) for a variety of different reasons, and I've seen this similar problem elsewhere.

In my render function, you need to use ofType like so:

let render () =
  ReactDom.render(
    ofType<App,_,_> "Counter" [],
    document.getElementById "root")

This get things to render, but nothing happens when you click on the buttons. So to try and fix this, I changed my state from an int to an object, and still get a runtime error.

nojaf commented 3 years ago

It seems like you are using a rather old version of Fable.React, what version of Fable itself are you using? It became a bit easier to create a function component in Fable 3.

Montana commented 3 years ago

Hey @nojaf,

This was the spot on answer. I've set up CRON jobs to update specific libraries, and I happened to not put Fable.React in there, I was using Fable 2.0 after running a version check.

I have now retried what I was trying to accomplish, and much easier. Thank you so much!