[Call for help] Test the React JSX v4

Being able to directly write a component like this is great for some cases, but usually I’d rather stay with @react.component so that the compiler can infer the prop types and I do not have to spell them out myself.

So in this example I’d stay with

module Component = {
  @react.component
  let make = (~x) => React.string(x)
}

But in future, we might be able to go without @react.component entirely.

How could this work without having to spell out the prop types explicitly every time?

1 Like

Indeed it is:

1 Like

You can use the same trick used by JSX:

module Component = {
  type props<'x> = {x:'x}
  let make = props => React.string(props.x)
}
1 Like

So you still need to write the props explicitly and just allow them to be polymorphic? That’s a lot less comfortable than just writing @react.component

1 Like
module Component = {
  type props<'x> = {x:'x}
  let make = props => React.string(props.x)
}

Whenever I look this implementation, the expressivity looks quite improved to me, even without @react.component attribute. The empty record type and value would make the expressivity better.

1 Like

Your trick with type variables to enable type inference works very well.

1 Like

Can you try this with latest compiler#master and rescript-react#jsx? I expect this issue is fixed now.

I expect that this issue is also solved with latest compiler#master and rescript-react#jsx.

It is fixed Add missing toplevel "jsx" to build schema. · rescript-lang/rescript-compiler@0d0333d · GitHub

Great! Thanks a lot! I did a retest and it does look good now. I just came across another issue. For some components, I got the error message

  The value createElementVariadicWithKey can't be found in React

  Hint: Did you mean createDOMElementVariadicWithKey?

Also, I had to modify code that uses React.Context.provider. I think the definition of React.Context still needs to be adapted to fit JSX4.

1 Like

Oops, there was a typo, I fixed it in the rescript-react#jsx.

Is your code something like this? And changing 1 to record fixes the error?

module C = {
  let context = React.createContext(() => ())

  module Provider = {
    let provider = React.Context.provider(context)

    @react.component
    let make = (~value, ~children) => {
      React.createElement(provider, {"value": value, "children": children}) // <--1
    }
  }
}

I think I need to tell this case is the breaking change by V4 which is using the record instead of object for props.

Thanks! Yes, my code for the context provider is like this, and changing to record fixes the problem.

About the new handling of key:

In JSX v3, this used to be zero cost, the key was just included in the props object literal.

In JSX v4 classic mode, there are now helper functions used that will cause additional overhead:

function createElementWithKey(component, props, key) {
  return React.createElement(component, Jsx.addKeyProp(props, key));
}

function createElementVariadicWithKey(component, props, elements, key) {
  return Caml_splice_call.spliceApply(React.createElement, [
              component,
              Jsx.addKeyProp(props, key),
              elements
            ]);
}

This does not seem like an improvement over JSX3. At least I think we should inline these calls, and use Js.Obj.assign directly or define Jsx.addKeyProp as an external based on Object.assign. (But the Object.assign itself is already overhead.)

In JSX v4 automatic mode, this problem does not exist, as the key is passed as a separate arg to the jsx function).

Good catch! Yes indeed.
Actually, external binding was not tried. I’ll give it a try.

I meant not just inlining the Object.assign, but couldn’t we also get rid of the helper function createElementWithKey by having the PPX directly generate

React.createElement(component, Object.assign(props, key));

?

No we can’t get rid of it.

This is done and merged into the compiler#master which is not published to npm yet.

1 Like