Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
JSX in detail (klipse.tech)
129 points by Pishky on Sept 8, 2017 | hide | past | favorite | 67 comments


Note that JSX is not limited to React. You can use JSX (or TSX in the case of Typescript) as a better replacement for Moustache or Handlebars. See here: https://github.com/wisercoder/uibuilder


I didn't think JSX made sense until I used it in Typescript (TSX). Having type safety and refactoring support in views and templates is wonderful. I know that both Vue and Angular have worked to build Typescript compiler plugins to support type checking their view files, but TSX is out of the box, has great editor support, and gives you the full power of Typescript's downleveling transpiler, too.

For what it is worth, the project I'm primarily using TSX in isn't using React either. It's built with Cycle.JS which uses competitor virtual DOM Snabbdom.


Has anyone else made the switch from JSX to hyperscript? JSX works well enough, but I love the consistency and composability of building views with plain old functions and data structures.


I switched the other way, as JSX fixed the main problem I've had for years using "hyperscript" (or DOM builders, as we used to say). Its comma-free syntax sugar for function calls, element lists and attribute objects makes it so much easier to write and maintain.


Yeah, I wrote about it last week:

https://medium.com/@alexkrolick/writing-react-components-for...

"Overall it's not a bad experience. JSX makes HTML feel more at home, but tends to obscure the underlying Javascript. Composition and higher-order components are more obvious in plain JS. If I was writing a library using those patterns heavily I might be tempted to go JSX-free even if bundling with Webpack + Babel."


There are a number of template languages that compile to hyperscript, I use jade/pug [0]. I haven't had to change my templates in years but I can still take advantage of virtual DOMs like React.

Before hyperscript, there was Templatizer which also compiled templates to JS functions. There are numerous good reasons to be able to manipulate templates easily as functions. Nevertheless there are numerous good reasons for templates (e.g. my designers don't need to know JavaScript, template languages last longer than JS trends, etc.).

[0]: https://github.com/nextorigin/gulp-pug-hyperscript


JSX is just 'plain old functions' - just with some syntactic sugar on top to make it a bit easier to write. In fact, JSX compiles down to functions looking very similar to hyperscript...


Our team moved from hyperscript to JSX as well.

Personally, I find JSX much more readable, and there was little love for hyperscript on the team.


Experimenting with JSX has introduced me to two language constructs: the Pragma, and the Macro. I know that these might seem a bit pedestrian to most folks, but they opened up my understanding of programming languages considerably. I am genuinely a bit surprised that the Javascript community hasn't played around more with the possibilities that both can offer.


In LISP based languages like ClojureScript, macros are part of the language. No need to build tools like JSX (that requires to run on webpack + IDE tooling etc...).


In Lisp, if you created something like JSX, your IDE or text editor would still be unlikely to understand it, as it'd be a very complicated reader macro. It doesn't magically solve all macro problems.

Doing it the Lispy way, though, you'd likely use sexprs directly, with maybe some normal macros, so you wouldn't have HTML-like syntax but would have something that worked nicely in your editor.


SXML has been around a while, and makes working with HTML in most Lisps a breeze. See this for example [0].

    '((html (head (title "My Title"))
         (body (@ (bgcolor "white"))
               (h1 "My Heading")
               (p "This is a paragraph.")
               (p "This is another paragraph."))))
[0] http://www.neilvandyke.org/racket/html-writing/


Lisp comes with a built-in templating system: quasiquote. Systems such as SXML (an s-expression representation of XML documents) build on top of that. This takes care of multiple problems with JSX: 1) writing HTML/XML is annoying (remembering to put the close tag in the right place, etc.) 2) JSX is a DSL, not an embedded DSL, so you need new compiler infrastructure to work with it.

Here is a snippet of real code that produces an SXML tree. It generates atom feeds for websites that use a static generator I wrote:

    `(feed (@ (xmlns "http://www.w3.org/2005/Atom"))
           (title ,(site-title site))
           (subtitle ,subtitle)
           (updated ,(date->string* (current-date)))
           (link (@ (href ,(string-append (site-domain site)
                                          "/" file-name))
                    (rel "self")))
           (link (@ (href ,(site-domain site))))
           ,@(map (cut post->atom-entry site <>
                       #:blog-prefix blog-prefix)
                  (take-up-to max-entries (filter posts))))
By far the best templating system I've ever used.


They work something like this in LISPs, right? Like, can you define new language constructs with them?

http://www.red-lang.org/2016/12/entering-world-of-macros.htm...

(BTW, have a look at red for desktop apps, it's not even at 1.0 and already fucking amazing)

But on topic; Are Macros a well-defined "thing"? Since a macro in C, seems to be rather different from a RED or LISP Macro.

Or is it just that C macros are essentially the same, just more restricted?


C macros are text substitution, implemented in a separate less-expressive language (the C pre-processor).

Lisp macros access the input program fragment as structured data, and manipulate that using the same Lisp functions and data structures that you use for regular, normal Lisp code.

I think that both forms are technically Turing-Complete, but Lisp is more expressive. In particular, it's much more common to see Lisp macros that destructure and reform their inputs, where C macros tend to see their inputs as black boxes that can't be opened. The textual-substitution model of C also has some extra perils, because code fragments can be context sensitive (such as creating identifiers that are already in scope).

In both cases, Macros are well-defined "things" in the sense that they are thoroughly defined in their respective language documents, but in both cases they are not first-class language items because they don't exist at run-time.


I could be wrong, but I don't think a LISP macro can transform the structure of the code in the same way that the JSX pragma turns an XML tree "inside-out". For example here's the source for the Babel JSX transformer:

https://github.com/babel/babel/blob/master/packages/babel-pl...


A lisp macro see a code block as a tree of symbols/primitives. It can do anything. This means that it is easy to write a library with a nice dsl, but hard to read other people's code.


> A lisp macro see a code block as a tree of symbols/primitives. It can do anything.

No, a regular macro still needs to be syntactically sensible. To handle arbitrary non-lisp syntax you need your lisp to support arbitrary reader macros (as in Common Lisp or — I believe — Racket) and that gets significantly more complex and involved and requires extensible/pluggable parsing.

Scheme does not have that for instance, SFRI-10 reader macros need to be wrapped in `#,()`, you can't just dump JSX or XML in Scheme source and expect it to work.


> Scheme does not have that for instance, SFRI-10 reader macros need to be wrapped in `#,()`, you can't just dump JSX or XML in Scheme source and expect it to work.

That's not 100% true.

See SRFI-105 which gives you infix expressions without needing to wrap them, and mixing and matching is supported the moment you dive into reader macros.

    #!curly-infix
    (+ 2 {a + b + c})
You do need to enable the reader modification, either in your own read (useful if you want safe eval, and parsing in limited environments), in which case you'd just provide an argument to read, or if you want it globally it'll probably just look like:

    #!jsx
    DOM.render(
      <h1>Hello world</h1>,
      document.getElementById((string-append "hel" "lo"))
    )
Writing the reader would be considerable work, but hardly impossible for Scheme to play nicely.


The usual macros in Lisp get all of the code as data, making rearrangement of the tree fairly trivial. For syntax changes, you'd use reader macros, which essentially involve writing a parser for all the parts that aren't Lisp. Once that's done, which is non-trivial, you would again have a tree to rearrange as you saw fit.

However, you'd be very unlikely to make something as syntactically heavy as JSX in Lisp. Lisp ethos is to keep the syntax as simple as possible, so it stays out of the way.


JSX could be language-integrated (witness the now-deprecated E4X for XML literals in Javascript), it just is not.

And most lisps don't have unfettered reader macros which would allow embedding macros using non-lisp syntax (aka JSX).

A macroed JSX wouldn't make much sense in Lisps really, and AFAIK isn't used with most clojurescript vdoms using either hiccup structures or regular function calls.


who needs JSX when you have hiccup!


Possibly a more uniform treatment of components versus "literal elements", but yeah the value proposition becomes very low.

In fact I'd argue the value proposition of JSX is already relatively low when you factor in hyperscript in regular javascript (and yes there are component-compatible hyperscript helpers for React).


I think that Hiccup's idea of writing the tree as a tree-like data structure is superior to writing a tree of function calls.

I tried doing something similar in JavaScript; the result looks a bit silly (I realized the elegance of not needing to delimit lists with a , in LISP right here) and has questionable performance: https://github.com/Lokeh/hux


I'm not sure what exactly you're referring to by macros. A container for boilerplate code to avoid repetition, as in templating languages? If so, the React solution would probably be extracting a simple component which just provides markup.


Here you got me interested in this post hoping it would use JSX to introduce Pragma's and Macro's, turns out it just reiterates what JSX compiles down to...


Here is the author of the Klipse plugin[1] that powers the interactive code snippets.

I've opened a github issue[2] to suggest to integrate the Klipse plugin on react.js official documentation. If you like the code interactivity, feel free to express yourself on the github issue[2].

1: https://github.com/viebel/klipse 2: https://github.com/facebook/react/issues/10646


Another good resource to learn about JSX (by the author of Preact): https://jasonformat.com/wtf-is-jsx/


Gave a talk at React Rally that goes over this briefly. https://github.com/hzoo/so-how-does-babel-even-work, and a basic version of the actual Babel transform: http://astexplorer.net/#/gist/ccb201a61db3d581c8be3161bf7806...


Hyperscript markup looks like a nice replacement for JSX. The source for hyperscript-react is 50 lines of code, including comments and empty lines, so it's fairly easy to learn:

https://github.com/mlmorg/react-hyperscript/blob/master/inde...


To me this looks much less readable than the equivalent JSX. JSX has been such a non-issue for me, it's extremely reliable and you can use all the new JS map/filters, loops, etc. instead of learning some half-finished template language.


> learning half-finished template language

javascript?


It may be fairly easy to learn, but mentally evaluating context during usage will be the friction much akin to HAML.


Thanks for posting this, it's a good read so far.

I have been using JSX quite a bit and this is helping me get a better understanding.


It's funny how, for years, we've been trying to get away from HTML mixed with code (specially in spaguetti PHP), just to get back to something similar again.


I used to think that way, but then you realize that JSX ends up behaving only as syntactic sugar for `React.createElement`.

If you have that clear, JSX is only syntax for the pure JavaScript you end up writing. Diving in the toolchain and ecosystem also helps you note that. Adding Webpack loaders to the mix, and then your application ends up only consisting of JavaScript files, where you abbreviate `React.createElement` with the old HTML tags.


You bring up a point that was discussed 35 days ago:

https://news.ycombinator.com/item?id=14925899

Tarikyn said: "Most developers I knew in person didn't care about CSS or didn't 'get' it."

Part of my response was:

"Some people looked at the chaos of non-standard HTML and decided the Web was successful because it had been broken from the beginning, and it had learned to work well while broken. I reached a different conclusion. It became clear to me that what developers wanted to do simply had nothing to do with HTTP/HTML. We don't yet have the technology to do what developers want to do. HTML was an interesting experiment, but it suffered from a dual mandate. Sir Tim Berners Lee wanted HTML to both structure data and also present it in graphical form. Almost from the start, developers were conflicted about which mandate they should obey, but the preference, since at least 1993, if not earlier, was to give priority to the visual. For all practical purposes, developers saw HTTP/HTML as GUI for IP/TCP. Previous IP/TCP technologies (email, gopher, ftp) had lacked a visual component, but HTML finally offered a standard way to send things over Internet and format the end result visually (emphasis on "standard"; I could insert an aside here about X window systems and some cool software of that era, but every app implemented their own ideas about visual presentation. X-Emacs, for instance, had its own system for visual formatting over a network)."

The point is, HTML was an interesting experiment, but we now know that it doesn't work for what developers want to build. So it is time to get rid of HTML and move on to something better.


Developers can build whatever they want with the html/css/javascript stack we have today, and they have.

Its up to you whether or not you write semantically pure html using display agnostic <div>, <article> etc. structural elements and only use css for styling. That is, after all, what they are for.

You can have what you want by simply pretending that browsers do not have default rendering rules, and not use the html elements that are arguably presentation only things, like <h1>, <table> etc.


HTML wasn't intended as an application platform, but for hyperlinked documents. That developers are using browsers for apps has economical reasons (eg. end users not willing to pay for software). That HTML isn't a good fit for a purpose it never was intended for is hardly TBL's fault, is it?


This is actually the misconception.

JSX is the template language of React. Angular and Vue use a template language on top of HTML. Neither of the 3 intermix business logic with presentation.

We shouldn't kid ourselves by talking of "code" not being a part of the templating as if SPAs magically come to life without code. Presentation has become more complex over time.


The struggle has been getting away from writing HTML in strings just like getting away from SQL in strings (excluding security/SQL injection reasons) which do not have handy IDE features like telling you that <cavnas> is not a valid HTML element.

JSX combined with an editor (Visual Studio Code + plugins) is nice because it does all of that highlighting and checking for you.


> It's funny how, for years, we've been trying to get away from HTML mixed with code (specially in spaguetti PHP), just to get back to something similar again.

The difference is that PHP+HTML is basically just templating. The HTML you put in PHP isn't a type that the interpreter is aware of and PHP isn't going to validate anything about.

Javascript used to have E4X in Firefox until it was removed when ES4 effort failed.

https://developer.mozilla.org/en-US/docs/Archive/Web/E4X/Pro...

Like someone said separation of concerns =/= separation of files.


spaguetti PHP has been replaced with PHP in templating. See Blade in laravel for example: https://laravel.com/docs/5.5/blade

So it totally makes sense to continue with this trend. Unless you have a very static website you don't really have a choice.

edit: woot, you don't use <? and ?> in Blade anymore?


I don't think you ever used <? and ?>. Only thing I recall is that there was a debate over double "{{" or triple "{{{" as the default for auto-escaping output.


JSX is not HTML. You are not writing HTML when you write JSX, you are writing Javascript. You are using a more convenient syntax to generate the virtual dom. All this hand wringing, navel gazing cargo-culting JSX gonna eat my baby bs is unnecessary. The PHP/html templating lessons of yonder simply does not apply.


> You are not writing HTML when you write JSX, you are writing Javascript.

And why the hell you have to write code in JS that will be ultimately represented as HTML? Is it because it simplifies some processes for the React's VDOM implementation? Don't you make your life harder in order to make React's life easier? If you say it's because you get template code linted in the same way as a regular JS code, I say that other frameworks also validate the templates doing AOT compilation.


The problem with templates is, ultimately, they end up re-implementing a lot of whatever programming language they're built in. Things like `{{%if}}`, `{{%for}}`, helpers, etc. are simply ways to write code in a template. Which is fine on the surface; these are features that meet the requirements of creating a UI, it's not like we'd want a templating system without them.

The issue is that now you have a ton of code (it is code, btw) living in a templating language that probably doesn't have as good of debugging, documentation, performance, encapsulation, composition, etc. as the underlying language it's using to process the template. It's up to the maintainer of the templating system to handle re-implementing that, and if you end up in a situation where it doesn't actually meet your requirements, you either have to add these basic language features yourself or start from scratch.

That's why things like React and Hiccup (and even more advanced, something like Racket), etc. have gained huge popularity and mind share: instead of re-implementing the programming language in a template system to show HTML, let's implement an embedded DSL to conveniently write HTML.

Then suddenly we get away from managing gnarly data dependencies, stack traces through templating systems, and writing stuff like this:

    {{%if medicare_eligible %}}
    <div>Here's some discounts!</div>
    {{% else %}}
    <div>You gotta pay full price</div>
    {{/if}}

    // ...
    templateSystem.create('template.hbs', { medicare_eligible: user.age >= 65 }

To just:

    if (user.age >= 65) {
      return <div>Here's some discounts!</div>
    } else {
      return <div>You gotta pay full price!</div>
    }
Once you are writing in an embedded DSL, you no longer need to worry about re-implementing all of the constructs of the underlying language; it's laid there at your feet.

Furthermore, by modeling your view as simple functions and data, you get all the features of data manipulation (huge productivity gain; don't need to write to rewrite or relearn `map`, `reduce`, `for`, serializing, etc.) and function composition (this is HUGE. I could write a whole blog post on this).


You are comparing with Handlebars templates, which bring an overhead on top of the HTML structure itself - in this case it makes sense to use JS instead of the custom syntax. But compare with Thymeleaf/Angular/Vue like templates - these are natural templates, you work only with HTML, controlling behavior using attributes which are part of the HTML.

> The problem with templates is

But the good part is that with natural templates you see stuff in a perspective and in a more plain/readable structure. It's like coding something in Assembler/low-level vs in Java/C#/JS.


What's natural about them? Controlling behavior through attributes is one of the silliest ideas invented, IMO.

I've used Angular - frankly, its template syntax is horrendous. I had to learn a ton of new semantics (`whatever` `(whatever)` `[whatever]` `#whatever` all have different execution contexts), and ultimately they've re-implemented most of JavaScript and* Angular inside of this HTML template syntax. Vue is about the same AFAICT. There's a lot of good in these frameworks, but templates is not one of them.

I don't understand your comparison to Assembler. How is this more like Assembly than a high level language?

React:

    return (
      <div>
        <button onClick={onSave} />
        {heroes.map(hero =>
          <button onClick={deleteHero(hero)}>{hero.name}</button>)}
        <form onSubmit={onSubmit}> ... </form>
      </div>
    );
Angular template:

    <button (click)="onSave($event)">Save</button>
    <button *ngFor="let hero of heroes" 
    (click)="deleteHero(hero)">{{hero.name}}</button> 
    <form #heroForm (ngSubmit)="onSubmit(heroForm)"> ... 
    </form>
Think of it like this: in templates, you write a string that will be tokenized and compiled into an AST, which then get interpreted by the host language. In React (or whatever other vdom-building library you want to use), you generate the AST using functions in the host language. This is simpler, more powerful, AND (in this day and age) easier to use.

Here's something neat about the React example, too: since it's a pure function, it can easily be unit tested without rendering to a DOM or doing some weird string stuff.


>Angular/Vue like templates - these are natural templates, you work only with HTML, [...] the good part is that with natural templates you see stuff in a perspective and in a more plain/readable structure

If you're using adjectives like "natural" without qualifying it with "in my opinion", it means you don't really understand the higher meta level discussion.

It is not objective fact that embedding a Turing Complete programming language inside of HTML via custom attributes such as Angular "ng-xxx" and Vue "v-xxx" is "natural". Many find it quite unnatural and unreadable![1].

If that's your personal preference, that's fine but be aware that many see HTML custom attributes to express a pseudo-language ("ng-for", "v-for", etc) is not really HTML. Yes, it's cosmetic HTML for appearances sake but not semantic HTML. The semantics is the pseudo-programming-language that's executed by Javascript. If you're unaware, the extending HTML with custom attributes for expressing code is an example of The Inner Platform Effect.[2] It doesn't matter whether you use new HTML custom tags[3] or custom attributes; that's just a difference in cosmetics.

[1] Examples:

https://news.ycombinator.com/item?id=10967000

https://news.ycombinator.com/item?id=10967789

[2] https://en.wikipedia.org/wiki/Inner-platform_effect

[3] tag soup to express a pseudo-programming language in HTML: https://blog.codinghorror.com/web-development-as-tag-soup/


> (this is HUGE. I could write a whole blog post on this).

and please do


>And why the hell you have to write code in JS that will be ultimately represented as HTML?

If an analogy helps, the React virtual-DOM is philosophically similar to the very old and industry-accepted technique of double-buffering[1].

Your question would be similar to asking, "why the hell do you write pixel data to an invisible memory buffer if you're going to ultimately display it on the screen?"

The plain old HTML specification invented by Tim Berners-Lee and the traditional HTML rendering engines do not have the concept of an invisible "compositing layer" with a formal API standardized across Chrome/Firefox/IE/etc exposed to programmers.

The vdom is the computer science abstraction to bolt on that "compositing layer" to HTML. The React loop then renders the invisible composite layer to the real DOM.

[1] https://en.wikipedia.org/wiki/Multiple_buffering#Double_buff...


> Your question would be similar to asking, "why the hell do you write pixel data to an invisible memory buffer if you're going to ultimately display it on the screen?"

That's not an argument. VueJS for example also supports the VDOM thing and it doesn't require you to write templates in JS code. My point is that React requires you to cook templates in the way that's is more convenient for the React (as with JSX React gets DOM/template model pre-validated, no mess with converting HTML code to the template model), not for the template makers.


>My point is that React requires you to cook templates in the way that's is more convenient for the React

And likewise, Vue.js requires one to "cook HTML" with extra Vue extended syntax such as "v-if", "v-else-if", "v-for", etc. to make it convenient for Vue.js. (See sibling comment from lilactown that went into more detail.)

Since you weren't questioning the validity of vdom but was actually wondering why one would write pseudo-HTML (aka JSX) if it's going to be ultimately rendered as HTML anyway, you can turn that around and ask, "And why the hell you have to write template v-xxx _code_ in HTML that will be ultimately executed as Javascript by the Javascript engine?"


> with extra Vue extended syntax

Syntax remains the same as it's still just HTML with a custom attributes.


I don't get this obsession with "just HTML". Is it just for its own sake? What tangible benefits do you get when it's laid out that way?

I am fairly certain the reason is not readability because a lot of people get by JSX just fine.


> And why the hell you have to write code in JS that will be ultimately represented as HTML?

I only use React for React-Native, so my JSX gets turned into native objects.

Have you ever written a non-web program though? The default mode for almost all native GUI kits is for developers to define the UI in code.

I've never, ever seen a UI designer or a high level DSL (like HTML) that works better than code for non-trivial programs. With JSX, HTML has finally caught up to the rest of the GUI programming world.


> Have you ever written a non-web program though? The default mode for almost all native GUI kits is for developers to define the UI in code.

Surely I have. I do understand that with JSX you get the valid template model, not the raw HTML that will need to be validated and converted into the template model then. That's actually what I meant writing above message - it makes React's life easier.


> it makes React's life easier.

It makes the programmers life easier by allowing JavaScript, not just React, to reason about GUI components before they are rendered.

You can use JSX with something other than React if you want to. React just happens to be the most popular kit that is using it right now.


Huh? If you want React to render a div somewhere you presumably have to say the word "div" to it at some point. Would you be happier just saying React.createElement('div')? Because saying <div> in the middle of your javascript code is simply syntactic sugar for createElement.


It never gets turned into HTML. It gets turned into JS, which, eventually causes calls to `createElement(...)` etc. to happen.

You are writing declarative code that says what the UI should do. It is NOT - and I cannot stress this enough - a "template langauge" in the same way as Handlebars or PHP. There is no string interpolation anywhere.


> It never gets turned into HTML

Really? So users get the JS code in the browser rendered in the same way as the code source looks, not the dynamically built DOM model which has the native representation form of HTML? Surely JSX is an abstraction layer on top of the createElement thing, and that thing is a part of the building strict template model scenario.


It's not the same thing. JSX is a user experience enhancement for developers.


PHP's everything-is-a-template philosophy is also a user experience enhancement for developers. React's nested components may provide a much saner rendering model than PHP's glorified string concatenation, but that's a separate question from how their templates are parsed.

PHP templates advertise, and do in fact provides, most of the same benefits as JSX. There are almost no new concepts to learn, the syntax is the same as the language proper, and developers have the full expressive power of that language at their disposal wherever they want it.

In practice, however, this seems to fail more often than not in a couple of ways. First, inexperienced developers (i.e. all developers at some point in their career) have a hard time resisting the urge to inline their business logic into their presentation logic. And second, the resulting templates are as often as not illegible, often requiring a reader to trace substantial chunks of tangentially related procedural logic in order to understand what will actually be rendered.

It's important to remember that PHP templates seemed like a good idea at the time. They did, and do, have real short-term benefits, and talented developers can leverage those benefits to great effect. But it turns out those benefits come with real long-term penalties, and besides, many developers are too green or too pressed for time or just don't care enough about the task at hand to wield that power consistently well enough to reliably reap the benefits in the first place. The PHP community has spent the last decade painfully crawling out of that tar pit; I'm not thrilled to see the JS community happily diving into it.


Well, I wonder where all the PHP programmers went...


Can't upvote this enough. Each time I try to dive into React/JSX I have some dark visions of PHP and JSP in my head.





Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: