WTH, You just called every web app I’ve worked on or built in the last 20+ years a toy project, even though they make money or were for major corporations.
This. Even if you start with
React.string
s (or some shorter aliases) everywhere, they’re much easier to replace with some localization helper than just raw “html-like” strings.
I’d safely bet that most apps are not some international success stories (or swiss) but internal corporate apps or b2b apps that have no use of i18n. Then there are apps that are targeted to a certain nationality or region that have no use of i18n. I’d say i18n is the rare exception for the totality of web apps and shouldn’t be the rational for a hassle for the majority of web developers.
Even if something isn’t localized text and content for anything I’ve worked on comes from a CMS, or in some cases a JSON file. I’ve rarely hardcoded text.
The app I am working on now uses markdown for all of the content.
I too work on a lot of internal company tools and we hardcode our strings, and I also wish I didn’t need to use React.string
This is because things can only ever be of 1 type in ReScript.
If the react compiler can convert <div>
into functions and correctly parse the types of <div className>
safely, can it also be smart enough to figure out that anything between tags not inside a {}
is a React.string
? Even if you still needed to convert non strings this would be a huge improvement on DX:
let counter = (
<div>
You've clicked it {React.int(count)} times!
</div>
)
I highly agree. Also, it’ll make it look more similar to how JS work, allowing to easily copy-paste code back and forth.
This exactly. As far as I can tell, this is a single radical change which Rescript made to the JSX syntax, and to me it looks like nothing but a footgun.
From this thread it sounds like the majority opinion is in agreement.
For one of my recent projects I have been using a markdown library to handle things like bold, italics, etc…
That’s what I’ve had to do in the past when using Elm, but that’s precisely why I like JSX, because I don’t have to go looking for third-party solutions to formatting large blocks of text, and I don’t have to give the client extra work parsing and rendering the markdown.
In any serious app you would need to support multiple languages
In my workplace we have a b2b product with a strong customer base, which has been evolving for 20 years, and >3 million LoC all-in-all, and we’re just starting to think about i18n. I think there is a huge gulf between “toy project” and “requires i18n” you’re missing.
I think what is happening is that it wants plain strings inside tags to be variables, so you can do
<div>x</div>
instead of
<div>{x}</div>
You can see this in the example from the docs. This doesn’t look like a necessity of the type system but rather an arbitrary choice.
let wrapChildren = (children: React.element) => {
<div>
<h1> {React.string("Overview")} </h1>
children
</div>
}
I see it as a small price to pay to completely eliminate “Objects Are Not Valid as a React Child” and preventing other runtime errors at compile time. My experience from onboarding multiple engineers to ReScript from 0 prior exposure is that it takes very little time to get used to.
It isn’t really a change to JSX syntax. All expressions inside JSX must be inside an expression container:
You can see this quite clearly using astexplorer
The example you have put looks more like a printer bug IMO than an indication the JSX PPX parser already handles JSX Children parsing to a union of JSXText / JSXExpressionContainer rather than the React.element type
I think measuring forum activity as a gauge of community consensus is a mistake–my experience has been people are busy building with ReScript and may not necessarily check in all the time.
I don’t get it. How do you get a runtime error by treating strings between tags as actual strings?
I think measuring forum activity as a gauge of community consensus is a mistake–my experience has been people are busy building with ReScript and may not necessarily check in all the time.
Absolutely. Sorry, my comment was a bit of a provocation but all I meant was: I feel strongly about this, and I’m glad I’m not the only one.
It isn’t really a change to JSX syntax
I don’t really understand your claim. In React…
function HelloWorld () {
const hello = 'hi there'
return <div>hello</div>
}
…will output <div>hello</div>
, whereas in Rescript…
@react.component
let make = () => {
let hello = React.string("hi there")
<div>hello</div>
}
will output <div>hi there</div>
. In React you need <div>{hello}</div>
for it to be a variable reference. In React <div>hi there</div>
will output just that; in Rescript it’s a syntax error. That’s the syntax change I’m complaining about.
Your AST screenshots seem to support this? In the first example {children}
is a JSXExpressionContainer
and in the second Hello
is a JSXText
.
Earlier I was claiming that it’s the only syntax change in resx compared to jsx, but of course that’s not the case. There’s the fact that <Thing value={value} />
in jsx becomes <Thing value />
in resx, while <Thing enabled />
in jsx becomes <Thing enabled={true} />
in resx. And I welcome that tweak, I do think it’s a bit nicer.
I wonder how much there’s a European bias thinking that pretty much any app has to use i16n at some point.
I don’t have strong opinions about all this, but I guess it would lower the barrier for newcomers to be able to just copy paste code from JS/TS.
We could make the formatter print curly brackets around variables first, then start introducing a syntax sugar that wraps characters between tags in a React.string
. But I might totally overlook crucial things here.
I do agree this is muuuch nicer compared to JS/TS. The whole thing about payload-less attributes in HTML/JSX is very ugly.
Pragmatically, the approach you suggest might be the best way to go, but my vote would be for no extra syntax sugar, just a breaking change to the syntax. I realise it would be a significant breaking change though.
I don’t think it’s just a convenience thing of “being able to dump HTML code in”, it’s fair bit of headache for readability and has an impact on correctness to have to break up strings and get the spacing right, as per my example in the OP.
I think if we do it step by step as @tsnobip said, by starting wrapping the variables in curly brackets. Then later it’ll be easier to add an ability to pass plain text.
what do you mean no syntax sugar? Down the line, semantic-wise, the text has to be of type React.element, so it has to be wrapped inside a React.string. What’s wrong with a syntax sugar? What would you replace it with?
Well I mean, JSX is itself nothing but syntax sugar, but I meant I don’t think we want to do anything extra to allow variable references outside braces and text nodes. Probably I misunderstood you.
Any child of a node in JSX (ie. any text inside a tag) which isn’t itself a tag or in expression braces, should unambiguously become a text node. That’s what we’re talking about, right?
Yes exactly, by syntax sugar I mean we would not need to explicitly call React.string anymore.
You actually made 3 nodes implicitly on here "You've clicked it "
, count
, " times!"
They are intepreted as text nodes in React DOM. As a result the spacing of the message is not preserved properly. So you eventually change it to You've clicked it ${count) times!
or add the white-space: pre
style.
This is actually a chronic problem with the React.ReactNode
type in regular JSX, which is never happened in ReScript JSX.
(Have you ever seen a dangling "0"
string appear somewhere in an app built with React? Same problem)
The suggested solution shouldn’t have the problem. The white-space: pre
is a valid point, but I think it’s worth sacrificing.