Complex bindings with the new [@react.component]?

interop

#1

Hi everyone, I am unsure if this is the good place to ask, or if I should go to stack overflow instead, but I have a question about the new JSX3 / react components interop:

The documentation states that “using a component written in JS requires a single external to annotate the types it takes”. But the example provided is most simple: a component with a single string.

How should we deal with more complex props that need some custom conversion work ? Before I would have written something like that:

[@bs.deriving jsConverter]
 type labelPos = [
   | [@bs.as "left"] `left
   | [@bs.as "right"] `right
 ];

[@bs.module "semantic-ui-react"]
external react : ReasonReact.reactClass = "Input";

[@bs.obj] 
external makeProps :
  (
    ~labelPosition: string,
    unit
  ) =>  _ = "";

let make =
    (
      ~labelPosition,
      children,
    ) =>
  ReasonReact.wrapJsForReason(
    ~reactClass=react,
    ~props=
      makeProps(
        ~labelPosition=labelPosToJs(labelPosition),
        (),
      ),
    children,
  );

The new way would look like:

[@bs.module "semantic-ui-react"] [@react.component]
external make : (labelPosition: string) => React.element = "Input";

But is there a way to provide a custom serializer for props using the new JSX3 interop ?


#2

You can just use an ordinary function where you do the transformation before calling the external. Something like this:

[@bs.module "semantic-ui-react"]
external make : (~labelPosition: string) => React.element = "Input";

[@react.component]
let make = (~labelPosition) =>
  make(~labelPosition=labelPosToJs(labelPosition));

#3

Thank you for that quick answer ! I indeed tried something similar, but forgot to move the [@react.component]annotation to my new make function… It works now and is still less overhead than the old wrapJsForReason technique.