[Proposal] Alternative 'React.createElement' api and JSX output
See original GitHub issueProblem
The current React.createElement api is quite limiting in regards of control flow statements.
Consider the following example
if (condition) {
<div>hello world</div>
}
will happily be transformed into
if (condition) {
React.createElement("div", null, "hello world")
}
but as soon as I try to wrap the very same JSX statement in a component (ex. a ‘div’) it blows up
<div>
{if (condition) {
<div>hello world</div>
}}
</div>
It would be transformed into invalid JS because of how React.createElement is set up
React.createElement("div", null,
if (condition) {
React.createElement("div", null, "hello world")
}
)
Workarounds
Of course you can workaround this issue by using the ternary expression (only usable for trivial ‘if bodies’)
<div>
{condition ? <div>hello</div> : null}
</div>
or a temporary variable (if the ‘if body’ is more complicated)
var conditionResult;
if (condition) {
conditionResult = <div>hello</div>
}
<div>
{conditionResult}
</div>
This ‘splitting’ of html hurts the readability quite a lot in my eyes. And worse, I am forced to do this ‘splitting’, there is no other choice 😦
…at least until now 😃
Proposed Solution
Change (or overload) the React.createElement signature from a list of childrens to a single append function
React.createElement(type, props, ...children) // current signature
React.createElement(type, props, appendFn) // proposed signature
How does this ‘appendFn’ approach work? Let’s explain it through examples:
// simple JSX
<div id="msg">
Hello
<b>World!</b>
</div>
// current JS output
React.createElement("div", {id: "msg"},
"Hello",
React.createElement("b", null, "World!")
)
// proposed JS output (using the new signature)
React.createElement("div", {id: "msg"}, append => {
append("Hello");
append(React.createElement("b", null, "World!"));
})
So ‘append’ does nothing more than what happens with the ‘…children’ in the old signature anyway. It appends them to the component. The big difference is, we are now in a function body instead of the limiting parameter list => big win!
Some more examples with control flow statements
// 'if' example
<div id="msg">
Hello
{if (condition) {
<b>World!</b>
}}
</div>
// current JS output is not valid :-(
React.createElement("div", {id: "msg"},
"Hello",
if (condition) {
React.createElement("b", null, "World!")
}
)
// proposed JS output is valid :-)
React.createElement("div", {id: "msg"}, append => {
append("Hello");
if (condition) {
append(React.createElement("b", null, "World!"));
}
})
// 'switch' example
<div id="msg">
Hello
{switch (value) {
case 'foo': <b>Foooo!</b>; break;
case 'bar': <b>Baaar!</b>; break;
default: <b>World!</b>
}}
</div>
// current JS output is not valid :-(
// proposed JS output
React.createElement("div", {id: "msg"}, append => {
append("Hello");
switch (value) {
case 'foo': append(React.createElement("b", null, "Foooo!")); break;
case 'bar': append(React.createElement("b", null, "Baaar!")); break;
default: append(React.createElement("b", null, "World!"))
}
})
// 'for .. of' example
<div id="msg">
Hello
{for (var person of persons) {
<b>{person.name}, </b>
}}
</div>
// current JS output is not valid :-(
// proposed JS output
// (now you can use native JS loops instead of depending on Array.map)
React.createElement("div", {id: "msg"}, append => {
append("Hello");
for (var person of persons) {
append(React.createElement("b", null, person.name, ", "))
}
})
Background
My roots as web developer lie in the Razor Template Syntax which allows to mix C# with HTML much like JSX does with JS and HTML. That’s why I felt a strong connection towards React right from the first day, because mixing a programming language with HTML already felt so natural. Now the only gap left to feel as flexible as back in the old days (with Razor) is this very issue I try to address here in this post. I hope you consider my approach and make React even more awesome than it already is! 😄
Issue Analytics
- State:
- Created 8 years ago
- Comments:6 (3 by maintainers)
Thanks for the info, happy to see discussions about it. And I can see do-expressions have even an implicit ‘return’, nice. (It almost looks like implicit do-expressions would do the job.)
As far as I’m concerned, you can close this issue.
I’m going to close this out, in favor of tracking it via the issues @syranide linked. Thanks.