@cknitt one might need an option to specify what packages do not inherit configuration.
E.g.: ["rescript-react-navigation", "rescript-react-native"]
Why would that be needed? If they don’t inherit the configuration, they will not work with the project bsconfig.json set to JSX4 anyway (error “The record field XXX can’t be found”, like I had on my first attempt).
You can set V3 mode in the middle of.a file.
The goal, however is achieved, is to have an escape route to continue using a dependency before it is upgraded, without getting blocked indefinitely.
Totally, my question was more regarding why the usage of labelled arguments altogether now that we have records in place. We could even remove [@react.component]
decorator altogether and keep just [@JSX] transformations?
Potentially simplifying externals as well.
As you well know, JSX ppx works in two parts, definition and application. @react.component
is for the definition and @JSX
is for the application.
-
@JSX
attribute is used by parser and ppx to transform the JSX expression<Foo />
to the normal function with react api. Actually, the parser parses the JSX expression into the normal function first, then ppx transforms it again with react API such asReact.createElement
. It is not only a substitution of babel transformation by the compiler, also it is a necessary preprocessing for type checking. -
@react.component
has more jobs to do. It transforms the labeled function into the function with one argument, the props in the record. And it changes the function name starting with the capital letter, which is valid to react API. The last job is to make the props type for the type checker.
We can write the react function component without @react.component
though, but it makes our life a lot easier. V4 transformation is using the record for the props argument, which is more clean and similar to the js representation.
I forgot to mention another issue that I encountered in yesterday’s tests.
@module("@react-navigation/native") @react.component
external make: (
~ref: ReactNative.Ref.t<serverContainer<'a>>=?,
~location: location=?,
~children: React.element,
) => React.element = "ServerContainer"
giving the error
Unbound type parameter 'a
Can this one and the issue with
~key: string=?,
giving the error
Two labels are named key
be fixed in the PPX?
Thank you for reporting the issue. I’ll look into it.
BTW, is the component implementation using React.forwardRef
though?
You can write this today:
module Component = {
type props = {x:string}
let make = props => React.string(props.x)
}
let _ = <Component x="" />
The one thing it’s missing is the component will not show up as called “Component” while it would if run through the JSX.
This is kind of still in progress. But in future, we might be able to go without @react.component
entirely.
We still need backwards compatibility though.
It looks very clean without @react.component
now!
Component
without @react.component
is transpiled to the below js output.
function make(props) {
return props.x;
}
var Component = {
make: make
};
...
React.createElement(make, { x: "x" }) <-- make
...
I thought it would not work and throw an error which is complaining about React component function name should start with the capital letter, but it seems fine in my example project. Not sure about it. I’ll look into it too.
Btw, it looks much improved and clean now.
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?
Indeed it is:
You can use the same trick used by JSX:
module Component = {
type props<'x> = {x:'x}
let make = props => React.string(props.x)
}
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
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.
Your trick with type variables to enable type inference works very well.
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.
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.