Alternative external component representation
ethul opened this issue · 3 comments
In addition to the representation described in #96 for foreign components, sometimes it is handy to represent an externally defined component as follows:
bar :: Array Props.Props -> Array React.ReactElement -> React.ReactElement
bar props children = React.createElement barComponent (Props.unsafeFromPropsArray props) children
someBarProp :: String -> Props.Props
someBarProp = Props.unsafeMkProps "someBarProp"
foreign import barComponent:: forall r. React.ReactClass { | r }In this representation one is able to pass any of the props defined in React.DOM.Props. This can be useful if the external component forwards props to an underlying DOM element, for example.
However, this representation fails to compile with:
[1/1 NoInstanceFound] src/...
75 bar props children = React.createElement barComponent (Props.unsafeFromPropsArray props) children
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
No type class instance was found for
Prim.Union t1
t2
( key :: String
, ref :: EventHandler (Nullable Ref)
| t0
)
The instance head contains unknown type variables. Consider adding a type annotation.
while applying a function createElement
of type ReactPropFields t0 t1 => ReactClass
{ children :: Children
| t0
}
-> { | t1 } -> Array ReactElement -> ReactElement
to argument barComponent
while inferring the type of createElement barComponent
in value declaration bar
where t1 is an unknown type
t0 is an unknown type
t2 is an unknown type
I am wondering if there is a way to implement this kind of representation or something similar.
//cc @natefaubion
This is fundamentally unsafe, so I'm not sure that a ReactClass is the best representation. I could see providing an unsafeCreateElement function without constraints, and for this case you would export it partially applied, rather than the ReactClass just as the DOM constructors are done.
module Foo (foo) where
import React (ReactClass, ReactElement, unsafeCreateElement)
import React.DOM.Props (Props, unsafePropsFromArray)
foreign import fooClass :: forall r. ReactClass { | r }
foo :: Props -> Array ReactElement -> ReactElement
foo = unsafeCreateElement fooClass <<< unsafePropsFromArrayYou don't have the issue with key and ref because those are props in DOM and are implicitly allowed.
Actually, you probably don't even need that. Since unsafePropsFromArray creates a { | r }, then you can just add a type annotation to fix r to (), and it would work.
Yes. You're right. Good call on the annotation. Thanks!
Full example:
module Bar (bar) where
bar :: Array Props.Props -> Array React.ReactElement -> React.ReactElement
bar props children = React.createElement barComponent (Props.unsafeFromPropsArray props :: Record ()) children
someBarProp :: String -> Props.Props
someBarProp = Props.unsafeMkProps "someBarProp"
foreign import barComponent:: React.ReactClass (Record (children :: React.Children))