fable-compiler / fable-react

Fable bindings and helpers for React and React Native
MIT License
275 stars 66 forks source link

JsInterop helper for wrapping a higher order component #213

Closed JordanMarr closed 3 years ago

JordanMarr commented 3 years ago

I saw a discussion from a few years ago about adding a built-in helper function for wrapping higher order components. Did that ever make its way into the library?

More specifically, this is the one I'm trying to wrap: https://github.com/bvaughn/react-virtualized/blob/master/docs/AutoSizer.md

alfonsogarciacaro commented 3 years ago

The are a couple of issues about it, for example #212. It's a bit tricky to support Higher Order Components out-of-the-box for several reasons:

Actually the sample linked doesn't look exactly as a HoC (at least to my understanding), just a component that accepts a function renderer as prop/child. I haven't tried it, but something like this should work:

// Bindings
open Fable.React

type AutoSizerProps = {| height: int; width: int |}
type RowProps = {| key: string; index: int; style: obj |}

let inline AutoSizer (render: AutoSizerProps -> ReactElement): ReactElement =
    ofImport "AutoSizer" "react-virtualized" null [unbox render]

let inline AutoSizerList (props: {| height: int
                                    width: int
                                    rowCount: int
                                    rowHeight: int
                                    rowRenderer: RowProps -> ReactElement |}): ReactElement =
    ofImport "List" "react-virtualized" props []

// Your code
open Fable.React
open Fable.React.Props
open Fable.Core.JsInterop

importSideEffects "react-virtualized/styles.css"

let list = [|
    "Brian Vaughn"
    // ...
|]

let rowRenderer (p: RowProps) =
    div [ Key p.key
          // Not sure how the styles are passed so I'm avoiding
          // the Fable.React Style prop which expects a list of CSSProp
          HTMLAttr.Custom("style", p.style) ]
        [ str list.[p.index] ]

ReactDom.render(
    AutoSizer (fun p ->
        AutoSizerList {| height = p.height
                         width = p.width
                         rowCount = list.Length
                         rowHeight = 20
                         rowRenderer = rowRenderer |}
    ),
    Browser.Dom.document.getElementById("example")
)
JordanMarr commented 3 years ago

Wow, thank you for the detailed response, and for the code!! 😃