Closed cmeeren closed 5 years ago
I found a way to do it, based on this function to get the properties of an object as a (string * obj) list
:
[<Emit("
var keys = [];
for(var key in $0){ keys.push([key, $0[key]]); }
return keys;
")>]
let toKeyValueList (o: obj) : (string * obj) list = jsNative
With this, I am able to expose e.g. getInputProps
with the signature seq<IHTMLProp> -> seq<IHTMLProp>
(instead of obj -> obj
) like this (taken out of context and somewhat modified for clarity):
let fableGetInputProps (props: seq<IHTMLProp>) =
props
|> keyValueList CaseRules.LowerFirst // convert to obj
|> downshiftGetInputProps // downshiftGetInputProps has signature obj -> obj
|> toKeyValueList // function defined above, we now have (string * obj) list
|> Seq.map (fun kv -> kv |> HTMLAttr.Custom :> IHTMLProp) // Convert to seq<IHTMLProp>
There's some more boilerplate in the bindings regarding converting necessary objects/functions between the public and downshift versions, but this is hidden from users.
Closing this, but do let me know if this is a bad way to solve the problem.
For the record, the bindings are now published as Fable.Import.Downshift.
OMG, why every React component library needs to invent their own way to pass props and children? 😬As commented here the Fable.React helpers use F# lists to be more idiomatic, but if you need to operate with raw prop objects, you can define your own domEl
that doesn't apply the keyValueList
transformation. For example:
let inline rawDomEl (tag: string) (props: obj) (children: ReactElement seq): ReactElement =
createElement(tag, props, children)
// Usage
let render rawProps =
rawDomEl "div" rawProps [p [] [str "A text"]
Yes, that could work, too. But I'd like the public API when used from Fable to be consistent with the F# list style. I'd say I managed to do this in a very nice way, which you can see from the Fable.Import.Downshift documentation and the comment above. :)
What will happen with render props (such as used by Downshift) now that hooks are a thing is another matter, of course.
I'm stuck trying to create bindings for Downshift. Have a look at the first example in the "Usage" section of the readme.
In short: The way Downshift works, is that the child of
<Downshift>
isn't a react component, but a function that takes an object – let's call itStateAndHelpers
– with various state and prop getters and returns a react element. That way, you can customize exactly how things are rendered, but let Downshift control the state and supply necessary props to the building blocks you want.Now, consider for example the following simplified code from the usage example:
getItemProps
is a property on theStateAndHelpers
object. It is a function which returns an object that contains necessary props for the list item component, and you pass it other props (such askey
above) that are merged into the final props for the list item component.What I am struggling with, is that
getItemProps
returns anobj
, notseq<IHTMLProp>
. The Fable react helpers acceptseq<IHTMLProp>
, notobj
. So it seems I can't use theli [] []
syntax, because I have no way (that I know of) of going fromobj
toseq<IHTMLProp>
.Are there good solutions to using a React component like
Downshift
in Fable, or is this bound to be a painful process?