elmish / hmr

Hot Module Replacement for Elmish apps
https://elmish.github.io/hmr
Other
28 stars 9 forks source link

Explore if we can shadow equalsButFunctions or FunctionComponent from Fable.React #26

Open MangelMaxime opened 5 years ago

MangelMaxime commented 5 years ago

Description

If you have a component like:

let private colorCircle =
    FunctionComponent.Of(fun (props : {| Rank : int
                                         Color : Color.Marker.ColorReferences
                                         OnPick : int -> unit |}) ->
        Button.button [ Button.OnClick(fun _ -> props.OnPick props.Rank) ]
            [ str props.Color.Name ]
    , "ColorSelector"
    , equalsButFunctions
    )

Then if you have an HMR call triggered the component instance in the DOM will not be re-render and still have a reference to the old OnPick callback. OnPick callback is created using dispatch for example ChangeColor >> dispatch.

The reason, is we are ignoring functions when determining if we need to redraw it.

We had the same problem with LazyView coming from Elmish and wrote our own version of it source

MangelMaxime commented 5 years ago

It seems like this code should do the job:

module HMR =

    let hot = HMR.``module``.hot

    /// Normal structural F# comparison, but ignores top-level functions (e.g. Elmish dispatch).
    /// Can be used e.g. with the `FunctionComponent.Of` `memoizeWith` parameter.
    let equalsButFunctions (x: 'a) (y: 'a) =
        #if DEBUG
            if hot.status() = HMR.Status.Apply then
                false
            else
                Fable.React.Helpers.equalsButFunctions x y
        #else
            Fable.React.Helpers.equalsButFunctions
        #endif

More thinking need to be done around the way to shadow the API and also if we need an inline call somewhere to make zero impact on production bundle size