question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[Proposal] Alternative 'React.createElement' api and JSX output

See original GitHub issue

Problem

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:closed
  • Created 8 years ago
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
osi-oswaldcommented, Sep 21, 2015

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.

0reactions
jimfbcommented, Sep 21, 2015

I’m going to close this out, in favor of tracking it via the issues @syranide linked. Thanks.

Read more comments on GitHub >

github_iconTop Results From Across the Web

React Without JSX
Each JSX element is just syntactic sugar for calling React.createElement(component, props, ...children) . So, anything you can do with JSX can also be...
Read more >
React Create Element - React Without JSX
Let's Explore the Important React Component “React Create Element”. A Step-by-step Guide on How to Create React createElement Without JSX.
Read more >
React equivalent of document.createElement()
I've had the same problem and came up with two solutions: Solution 1. 1. Import ReactDOM library: import ReactDOM from 'react-dom';.
Read more >
Emulating React and JSX in Vanilla JS
We will be using the GitHub Search API to fetch our results. ... React uses JSX, which is very similar to regular HTML....
Read more >
Getting started with React - Learn web development | MDN
React uses an HTML-in-JavaScript syntax called JSX (JavaScript and XML). Familiarity with both HTML and JavaScript will help you to learn JSX, ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found