Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Having to use stringToElement() is awkward #138

Closed
gaearon opened this issue Dec 8, 2017 · 13 comments
Closed

Having to use stringToElement() is awkward #138

gaearon opened this issue Dec 8, 2017 · 13 comments

Comments

@gaearon
Copy link

gaearon commented Dec 8, 2017

See this thread: https://mobile.twitter.com/Stealtheritz/status/938224539330326528
Warning: subjective opinions ahead!

This doesn't impact me directly, but having to use stringToElement() to add text always felt like "appeasing the compiler" kind of work that I would expect from a language like Java, not Reason. :-)

I have two issues with this API:

  1. I want to just use strings.
  2. The naming doesn't match my knowledge of React. A string is not an element. An element is an object that looks like {type, props}. A string is a string. You can't turn it into an element. A string is a React node though. You don't need to convert it to a node—a string is already a valid React node type. But if the compiler insists, I could see myself writing ReasonReact.text() for this.

By the way, I know I can write let s = ReasonReact.stringToElement() at the top. This feels like an afterthought to me. Yes, I could, but this just disguises the fact that the API is not ergonomic.

@pseudoramble
Copy link

pseudoramble commented Dec 9, 2017

This is also somewhat related - The docs here make it seem like it should be possible to do this (though it wasn't intentional according to the docs on this):

Note that due to current syntax constraints, you need to put spaces around the JSX children: <div> foo </div>.

It could help to point out why it's needed by linking ahead to where the docs talk about the render function, and perhaps point out the trick of making an alias to the function with a shorter name.

@aaronshaf
Copy link
Contributor

FWIW in internationalized apps we'll already want to write something else over it, i.e.

let i18n = FormatMessage.translate |> ReasonReact.stringToElement
<div className="title">
  (i18n("What to do"))
</div>

@kujon
Copy link

kujon commented May 27, 2018

Part of what makes Reason/OCaml great imho, is the lack of type coercion. The cognitive load is low, you don't have to learn tons of magic rules like in JS, you have to be explicit. Introducing an exception just for React risks taking Reason from the familiar syntax, into familiar syntax and behaviour territory. And the behaviour in JS is what makes it such a mad language sometimes.

You don't need to convert it to a node—a string is already a valid React node type.

This is because React embraces JS way of writing code. Input a 🍌 into a function, tons of validation rules run, and it will attempt to do what it thinks is best. While very handy, it gets confusing very quickly.

Personally, 👎 to most of the proposal, however this bit:

But if the compiler insists, I could see myself writing ReasonReact.text() for this.

looks very sensible.

@cnguy
Copy link

cnguy commented May 27, 2018

@kujon Latest version v0.4.0 of ReasonReact supports ReasonReact.string() now!

@skosch
Copy link

skosch commented Jun 6, 2018

ReasonReact.string() isn't the solution, and redefining it at the top isn't either.

Introducing an exception just for React risks taking Reason from the familiar syntax, into familiar syntax and behaviour territory. And the behaviour in JS is what makes it such a mad language sometimes.

JSX is the exception. It's markup, not code. Nobody has ever complained about JSX being a mad language; it was never broken, and it didn't need fixing type checking. The only thing that's mad here is having to tell the compiler that a literal hard-coded string really is ... drum roll ... a string.

Is there a technical reason we can't have standard JSX? With all (sincere!) gratitude and respect to the Reason team, what keeps you from addressing an issue that has nearly 50 thumbs-ups and is clearly a big turn-off for potential newcomers? Is there anything that can be done to help?

@cristianoc
Copy link
Contributor

reasonml/reason#1910

@gaearon
Copy link
Author

gaearon commented Jun 6, 2018

Can I ask Reason experts to clarify what this has to do with type coercion?

I don’t propose to coerce string to an object. I think what I’m proposing is more like making a node to be a union type of string and element. Which is my mental model from actual React.

@kujon
Copy link

kujon commented Jun 6, 2018

JSX is the exception. It's markup, not code. Nobody has ever complained about JSX being a mad language; it was never broken, and it didn't need fixing type checking. The only thing that's mad here is having to tell the compiler that a literal hard-coded string really is ... drum roll ... a string.

JSX is just a syntax sugar for createElement. In JS, you can do put almost anything as a child:

React.createElement('div', null, false);
React.createElement('div', null, 42);
React.createElement('div', null, 'dsadasd');

All Reason is doing here is just telling you that a child must be an array of React elements and putting you in charge of converting your data structures to it.

This is not that different to how you perform other conversions:

/* won't work */
let foo = "4" ++ 4;

/* this will */
let foo = "4" ++ string_of_int(4);

IMHO, we shouldn't try to make Reason behave like JS, because (as a JS guy myself), I feel like we've got a lot to learn from the OCaml community about how type-safe code works.

Edit: @gaearon this wasn't meant to clarify your point, but the point @skosch made.

As a Reason rookie, I'll attempt clarifying yours though: OCaml doesn't have a concept of anything | anything_else like Flow or Typescript do. If you're willing to write a union/variant, each member will be its own custom type constructor, which is always part of the variant, never to be used alone. So if you defined a string as part of type whatJSXAccepts = | string | reactElement(stuff), you wouldn't be able to use just string or just reactElement.

@skosch
Copy link

skosch commented Jun 6, 2018

So, not having looked into this in nearly enough depth – is this, in the end, simply a limitation of OCaml's type checker? I.e., that @gaearon's "union type of string and element" simply can't be done without explicit type annotations of some sort, because OCaml neither provides type introspection nor typeclasses-like polymorphism that will implicitly pick the right instance? And therefore standard JSX behaviour is just completely out of reach, at least with the current ppx infrastructure?

@cristianoc
Copy link
Contributor

@skosch that's correct.
We're looking in what's the smallest extension that would give us this feature, and ideally have other applications as well.

@texastoland
Copy link

texastoland commented Jul 16, 2018

Can I ask Reason experts to clarify what this has to do with type coercion?

@gaearon I'm not an expert but I think I can explain.

I think what I’m proposing is more like making a node to be a union type of string and element.

It sounds like you're thinking type node = 'a element | string. But in MLs (OCaml, Haskell, etc.) the branches are constructed with functions like type node = Element('a) | Text(string). You can already see the latter in ReasonReact:

and element =
| Element(component('state, 'action)): element
| String(string): element
.

Right now ReactElement.string is a white lie. It's a type coercion to reactElement:

external string : string => reactElement = "%identity";

Although JSX is a ppx (compiler macro) reasonml/reason#1910 (comment) sounds like it doesn't receive typings therefore it could only coerce string literals.

I agree it's awkward for newcomers.

@peterpme
Copy link
Collaborator

@gaearon This has been fixed and is now {React.string("hi dan")}

Would love to have you give Reason another go-around 😄 Thanks!

Closing out for now.

@MoOx
Copy link
Contributor

MoOx commented Apr 22, 2020

Even better imo {"Hi Dan"->React.string} :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants