101 comments

[ 2.7 ms ] story [ 175 ms ] thread
JSX? Typescript? What are you a noob? That was so 2016.

Come on, get with it - JSX 2.0, TypeScript 2.0, etc. is what real web devs use. That other crap is obsolete. This is 2017.

Edit: I'm parodying this:

https://hackernoon.com/how-it-feels-to-learn-javascript-in-2...

ye that's really funny and insightful, good job
The parody would be fair enough with different technologies, but these are mere version-bumps. Backwards-compatibility may not be absolute, but generally speaking if you understand the use-case for v1, there's not going to be a lot of cognitive overload in figuring out v2.
"What should go into JSX 2.0?" would be a much clearer title outside of the context of the GitHub issue.
Yup, even the issues not marked controversial seem so to me. I think JSX is quite nice but it has its limits/annoyances. One is obviously that it's not real HTML5.

I would like to see a successor that is more like HTML5 without the X. No idea how that could be realized though... ;)

Sorry, what do you mean by this? (For those unfamiliar with the deviations)
I started using React/JSX professionally in the last few months, so some of these are fresh in my head. Differences I'm aware of:

1) JSX creates virtual DOM objects, not HTML tags. In places where the DOM and HTML use different names for the same thing, JSX uses the DOM's name. In particular, the "class" attribute is called "className" and the "style" attribute takes an object like { color: "white" } instead of a string like "color: white" (and the keys are like "backgroundImage" rather than "background-image"). The latter rarely comes up, but the former bites me all the time when incorporating markup from designers.

2) JSX requires all tags to be closed, like XHTML and all XML dialects. HTML 5 declares some tags to be self-closing, like IMG.

3) JSX removes whitespace padding inside elements. This usually results in the same visual result, except for those cases where HTML actually cares about extra whitespace (like in PRE and TEXTAREA).

4) Regarding TEXTAREA, you're encouraged not to use the inner content of the tag to define its default value. Instead, you treat it like an INPUT. (I think this is if anything an improvement.)

5) INPUT tags have some special behavior related to default values, but that's really more about React than JSX per se.

Overall I have found JSX pretty easy to get into. I appreciate that it really is just a very thin layer over underlying JS. I'm not totally sold on this approach versus the many, many, many other HTML templating systems out there, but at least it's easy to understand.

Ah, I see, thanks for sharing. Yes, I personally view most of those deviations as positive.
Regarding 1)... like 5) that's React, so you could write a JSX transpiler that creates actual DOM objects.
(comment deleted)
The best approach I've ever seen is Wicket, where you write pure HTML with just ID attributes, and all the logic / control flow is in the code. But the code for a component corresponds directly to the HTML (by having the same filenames), and each component can be very small and self-contained / compositional. It ends up being the best example of the good side of OO I've seen.
Thank you, we've updated the title.
I definitely think fragments should be an added feature of a 2.0 version of JSX - just take a look at this Github issue that continues to house active discussion now for 2+ years.

https://github.com/facebook/react/issues/2127

Yes, this is often-requested. We don't necessarily need to change JSX to add this to React though. With our current implementation it's a pain to support it but we're working on it.
I wish it could be possible to write this:

const animal = "cat"; <Component {animal} /> equivalent to: <Component animal={animal} />

How about <Component {{animal}} /> ? Because that should already work, no?
You'd have to spread in the object, right?

<Component {...{animal}} />

Yes, absolutely. Ignore what I wrote.
We already do this when we have a lot of props to pass down. "A lot" usually means enough to take the line past 100 columns.

const componentProps = {}; <Component {...componentProps} />

IMHO This is way too insignificant benefit for a breaking change with this magnitude.

Using spread ( `{...{animal}}` ) is already working and it will stop working with the new syntax.

On top of that killing two brackets and three dots will not give you huge performance / code-productivity benefit.

Since when does Reason have JSX?
JSX is actually a generic transformation of XML like structures to function calls. Since it's mostly used with React, that's the default, but you can use any function you like. It's the "pragma" option in the config for the plugin.

https://babeljs.io/docs/plugins/transform-react-jsx/

Since Reason was written by Jordan Walke and Cheng Lou (creators of React and React Motion, respectively), that's unsurprising.
I'd like a good system for conditional child components. I liked Flex's system.
I like how the if proposal is down voted, probably because it's mentioning Angular. Conditional rendering in React is not always very clean. Most codebases end up resorting with something similar to this in a container to show a spinner while data is loading and rendering it when done.

<ConditionalSpinner renderIf={data}><PersonRenderer person={data.person} /></ConditionalSpinner>

Problem is that the inner component will still be parsed and fail with cannot read property person of undefined. Yes, you can do this with a simple condition in your render function, but then it's not declarative any more.

How about { data && <Inner person={ data.person }/> } ?
If you render a more complex component this introduces another level of indentation. I can see why some people would prefer cleaner code but in my opinion, indenting ifs is a good thing as it increases the readability and allows you to spot if statements faster.
this is why you should be using immutable js. It will not throw errors accessing an object.
(comment deleted)
(comment deleted)
It's the extreme fanboyism there! Wrapping every component that has `if` attribute with an `if` statement should not result into that:

    <div *if={cond1 && cond2}>
        <div>foo</div>
    </div>

    // results to
    if (cond1 && cond2) {
        return React.createElement('div', null, 
            React.createElement('div', null, 'foo')
        );
    }
I'm not sure why this is bad? Because it's looking like Angular?!!
I think ternary expression are rather ok here, though not perfect:

    {cond1 && cond2
     ? <div>foo</div>
     : null
    }
And you can inline if-statements with an IIFE when you need a little more space:

    {(() => {
      if (cond1 && cond2)
        return <div>foo</div>
      else 
        ...
    })()}
Though it makes GitHub think it's a Clojure file.

     {(() => {
     })()}
Honestly I can't decide if I think this is ugly or beautiful. It's like the buffalo buffalo of JS.
(comment deleted)
It’s interesting to see that there are so many ways of doing conditions in JSX. I myself wrote a tiny library (http://github.com/yuanchuan/cond) for it several months ago and thought it made the code looks clean but suffers the same undefined issue though.
It's bad because it's inconsistent with how every other attribute in jsx works. Nothing else in jsx changes the control flow of the code.
It is 2.0 so it can have breaking changes
The parent didn't mention anything about backwards compatibility. They're saying 2.0 with such a change would be inconsistent with itself. And they're right.
<div if={expression} />

translates to

React.createElement('div', {if: <expression>})

This is bad because createElement always gets execute, whether the if expression evaluated to true or false. Changing this semantic would be messy.

I'd love for them to adopt something similar to Razor (Microsoft server side html engine)

note: i've changed your example to show code inside html tags, i'm aware it does something different to yours.

conditionals

  <div>
    @if(cond1 && cond2) {
      <div>foo</div>
    }
  </div>

loops

  <div>
    @for(var i in collection) {
      <div></div>
    }
  </div>

variables

  <div>
    @variable
  </div>

ternary/longer statement

  <div>
    @(variable ? 1 : 2)
  </div>
The one negative thing I've found with Razor is the ambiguous start and end of statements or expressions vs html. Sometimes a @ is required before a statement and sometimes its a syntax error, conversely statements and and expressions may be rendered as text if they follow html with a @. I think jsx's approach is clearer.
admittedly there is the occasional moment I hit where I need an extra @ or @: so it's not perfect, but I have much less issue reading that format than the { true && <element /> } syntax, also think @if is a lot nicer than <if>.

Maybe just a personal thing.

Now that sweet.js supports babel, the best option may be to write an if expression macro.
The Flex method of conditional rendering is nice, far better than ng-if all over the place.
Loading (and error, etc) state should be the responsibility of the component doing the content rendering, not the parent. So the ConditionalSpinner component:

   <ConditionalSpinner renderIf={data}><PersonRenderer person={data.person} /></ConditionalSpinner>
Could be written better as:

   <PersonRenderer person={data.person} />
Where PersonRenderer would be defined as such:

   class PersonRenderer extends Component {
     render() {
       if(this.props.person) {
         return <div>personcontent</div>
       }
       return <LoadingIndicator/>
     }
   }
Given this, I'm still not sure how an If "component" would be achieved (and further, you'd need an Else or a Switch component anyway if going down this route). Maybe you could explain the benefits of such a path?
> Loading (and error, etc) state should be the responsibility of the component doing the content rendering

It's often divided in two: One container fetching the data, and a pure component rendering it.

I think my intent might have come across wrong here.

The "states" aren't related to container/dumb components or data-fetching/selection logic. They're purely about rendering the state for a given segment of the page. Perhaps this article[0] might help convey my intent. It's more about how to render "we didn't get data from that one endpoint for this section of the page" or "we're waiting for the data to show up", etc.

[0]: https://medium.com/swlh/the-nine-states-of-design-5bfe9b3d6d...

or create a wrapper function ...

  function withLoadingIndicator(Wrapped) {
    return function(props) {
      if (props.loading) {
        return (<LoadingIndicator />);
      }
      return (<Wrapped {...props} />);
    }
  }

  // ...

  export class PersonRenderer extends Component {
    render() {
      return <div>personcontent</div>
    }
  }

  export default withLoadingIndicator(PersonRenderer);
I first learned about this method with react-dnd and have used it extensively since. Quite elegant.
JSX shouldn't be used to turn a component into a controller for child components. That's why I wouldn't want that kind of logic in there.
You think it's downvoted because it mentions Angular? Baseless complaining. JSX is a breath of fresh air after all the templating languages that force you to learn a crippled pseudolang. What's next? For loops? Moving every feature that already exists in JavaScript into JSX with some arbitrary additional syntax? What's the point? It's already very easy to do conditionals with && or ternaries.
You can already do that...

    function ConditionalSpinner({renderIf, children}) {
      if (!renderIf) return null;
      return children[0];
    }
In what sense is it not declarative anymore?

I usually use tests at the top of the render function to make sure that data is there, and return cleanly if it isn't. It just makes development easier as React components tend to get re-used. Within the data.person, in your example, the caller should make sure that it is complete, or pass nothing at all.

In the case you show I would either return <Spinner/> or the content, but never nest them. Have a conditional and two return statements, or one return statement with a ternary operator.

I down voted that proposal as well, but not because the mention of Angular, but because I don't like the `ng-if` way of doing conditionals. One of the reason I like JSX is because it is "just Javascript". Putting the flow control logic into component attributes like that is a terrible idea for JSX.
I actually generally include this in my Babel configuration: https://www.npmjs.com/package/jsx-control-statements.

People might argue that this isn't the React way of doing things, but it's easier than setting a conditional classname to display none. It's also easier than breaking out a small amount of html into a separate component just because you want some conditional display logic.

Conditional rendering is all I really hurt for. But I would prefer not having a 2.0 at all if it wasn't fully backwards compatible.
Also keep in mind that javascript engines have a built-in mechanism for including multi-line strings with a powerful substitution engine: tagged template strings (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...). The upside of template strings is that you can run your code directly in node or electron without using extra tooling first. It is possible and not hard to use tagged templates with react, although few people do. It's more common in some other frontend ecosystems.
JSX isn't templating. It's representing a virtual dom tree of function calls with a syntax more representative of the resulting markup.
Some kind of way to parse variables only if they exist. The equivalent of (in Coffeescript)

a = {b:'c'}

a?.c //undefined

a.b //'c'

b?.c //undefined

Correct me if I'm wrong, but that doesn't seem like the domain of JSX. That's just JavaScript.
What could be safely removed from JSX?
(comment deleted)
Regardless of the changes, I really think that this is very well managed community wise, not strictly comparable, but hopefully stuff like this will avoid fragmentation of the community like angular 1/2, python 2/3.
tldr: "I think it is probably only worth doing as a batch when the accumulated amount of changes makes it worth while. We have accumulated a number of these nice-to-haves breaking changes that would be nice to incorporate. However, at this point JSX is a hugely adopted syntax in all kinds of tooling."
Nothing. Seriously, JSX works really well as it is. These proposals seem like small enhancements, some of them for the wrong reasons.

> Computed attribute names.

If you need this, you're probably being too clever. If there's a legitimate use for this, I've never seen it in the past 2 years I've been using JSX with React.

> Object short hand notation.

> Drop the need for curlies around attribute values if they're a single literal, or parenthesis.

Is it really that much more work?

> Implicit do expressions.

> Conditionals

> Loops

If you need control statements in your JSX, you're doing it wrong. When you need these things, this is a sign you need to break your code into smaller chunks. Move this logic into separate functions, lambdas or variables and interpolate them in. Now you've labeled your code and made it more composable. This is called self-documenting code and it's a lot easier for others and your future self to read.

All of these wouldn't be so bad if it wasn't a proposal to justify breaking changes. I really don't want to have to deal with two versions of JSX that are incompatible. That just sounds like hell.

Agree wholeheartedly - this smacks of the repeated mistake that most template tools make which is trying to do language logic inside.

The whole point of JSX is that it isnt a template language and is just a wrapper around objects with properties.

Most template tools made the major mistake of existing. They start out as some attempt to limit the functionality available in templates but pretty soon they always add functions and conditionals and formatters etc... ending up with what is essentially a turing-complete language, except needing an extra step to parse, less well tested and usually much uglier than the host language.

Oh, and you have to learn it as well, because someone had a fetish of avoiding python/php/perl/... in templates, inventing <loop start=1 end=15 step=1> to replace (1..15).each.

Nowadays we're replacing loops with recursion or map but fundamentally, there's no difference. If you have a collection and you want to render it, you need the logic of repetition in a template, and there's nothing wrong wit h putting it there.

10 years ago, you would often see html with interspersed business logic, even SQL. That just doesn't happen anymore. Now, fruitless attempts to further reduce logic in templates just lead to convoluted overengineering who at best try to hide the logic.

> Most template tools made the major mistake of existing.

haha, harsh. I don't disagree but there are cases where they make sense (pure, designer focused, flows for example). But anywhere where a dev will be involved generally a template language is solving the wrong problem.

JSX is quite an elegant solution to the issue: provide abstraction, but allow underlying logic to be in the same language.

I'm inclined to agree on all these points, but I do end up doing most of these things now, in one way or another.

For loops I'll create a collection of items in a function (usually done with map against a prop collection) and drop that variable in my JSX.

Basically the same for conditionals. If I want a thing, a var gets a component assigned. Otherwise it's null.

Are these bad patterns, as is?

No, these are good patterns. You've taken an otherwise large chunk of code and broken it down into comprehensible pieces that can be composed together and tested individually. This also leads nicely into refactors, where you can extract these smaller chunks into new components when your old component is handling too many responsibilities.

Unfortunately if control flow gets bolted onto JSX we can expect to see a lot less of this. Others will assume that this is the way business is done. That is, creating hundreds of lines of hard to follow conditionalized pseudo XML. I realize this already occurs in more bastardized forms, but it shouldn't be encouraged by new language features.

Yep, how do we vote against logic inside jsx markup?
(comment deleted)
I personally agree with this in the big scheme of things. Computed attribute names seem overkill and I worry about adding logic to JSX. But, honestly, I could care less if they were added if such features get other people all fired up.

My personal taste though often does wish for object shorthand and dropping curlies. My sense off the top of my head is that the majority of my actual props look something like `<Widget user={user} id={id} timestamp={timestamp} />` since I mostly avoid setting up data inside JSX. Is it a big deal? Of course not. But it would be nicer to just write `<Widget user id timestamp />` or `<Widget $user $id $timestamp />` or whatever syntactic sorcery would be settled on.

A modest advantage of dropping curlies is it reduces the already tiny force of one argument for styling in CSS over JS: "prettier and less typing". I certainly don't think they should be dropped just for this reason of course, but could be a side effect worth noting.

It's worth noting that if you want to go above and beyond what JSX gives you, it's not hard to write a Babel plugin to make the syntax more trite. You could (relatively) easily write "the coffeescript of JSX" that compiles to vanilla JSX if you want something that's "prettier and less typing" while not making it the standard.
Standard syntax sugar is good not because syntax sugar is hard to accomplish, but it's something everyone implicitly agrees to understand. Custom schemes are not as maintainable
I'd otherwise agree, but JSX is already syntax sugar. Once you start making the syntax ambiguous or minimalist to the point of confusion, you should break off into a new syntax.
You can do `<Widget {...{user, id, timestamp}} />`
Oh man you're right aren't you! I just might start doing that!
It does seem really good right now. If they go crazy imperative on it, they'll end up with jsp. If they go crazy functional on it, they'll end up with xslt.

I'm good with how it is right now. The sour stuff is in the js, and the sugar in the jsx.

What's wrong with just using the JavaScript/TypeScript syntax you already have? It's trivial to write a few functions to create HTML elements and append children. For example:

    import { h1, div, span, text } from 'html';

    const user = { name: 'Dave', age: '30' };

    return div('container',
        h1(text('User info')),
        div(span('field',text('Name')),text(user.name)),
        div(span('field',text('Age')),text(user.age)),
    );
I don't understand why there's so much activity in creating new languages/language extensions that duplicate functionality that can already be expressed as is, with just a bit of basic library support.

CSS preprocessors are another example. Want to add loops, conditionals, and user defined functions to your CSS superset? Why not just use JS/TS instead, which has all the control features and can output CSS text just as well as Less/Sass/SCSS/flavour of the month.

You just wrote elm code in javascript
That style was old before Elm. Elm does it rather well tho
Mithril does this, and I find its syntax much cleaner and easier to write in than JSX.

        view: function(ctrl) {
		return m("div", [
			ctrl.pages().map(function(page) {
				return m("a", {href: page.url}, page.title);
			}),
			m("button", {onclick: ctrl.rotate}, "Rotate links")
		]);
	}
http://mithril.js.org/
Just one thing: ability to return array of elements as result.
My only real gripe about JSX is the crazy attribute casing rules. If it looks like HTML then attributes should be case-insensitive just like HTML. The worst of it is (unless this has changed) they are just silently dropped without any error message.
The React ESLint plugin's no-unknown-property rule is handy for catching (and automatically fixing) this:

https://github.com/yannickcr/eslint-plugin-react/blob/master...

Good to know, thanks.

That's a good stop-gap, but the tool itself should either pass through everything to the HTML or throw errors on anything that isn't going to get passed through. The silent failure mode is a UX bug.

Absolute inelegant shit, use Elm