JSX is no longer my friend
medium.com
medium.com
I've been using JSX since React 0.4. React's greatest strength is its simplicity. You can read all of React's documentation in 20 minutes. There's hardly any learning curve compared to the larger JS frameworks out there. It's all just JS*--no "logic-less-ish-kinda-sorta" template for loops, or two way data bindings, or figuring out when to render.
I don't think JSX is the terrible problem the hyperscript people make it out to be, but I think it might be time for it to retire. While JSX is as mild as learning curves come, it's still a learning curve. It still requires transpilation. It requires the extra characters. To reframe the conversation, does it make sense for the learning curve to be "it's HTML-ish with caveats like camelcasing but it works like JS" or "it's a collection of functions that generate HTML that are named for the HTML tag they generate."
I'm also really interested in the "but it makes sense to designers" argument. Is that actually true? Are there designers out there who understand JSX but wouldn't understand well formatted hyperscript? I feel like that's saying "yah I get ERB but HAML doesn't make any sense."
Again, I don't think this is a big enough deal for the amount of attention it gets paid. I'd love to see the React team bring in first class hyperscript-like syntax that is 100% JS, but it's hardly a reason to not use React.
It may have helped that we converted an existing code base (so there was a lot of html-as-JS example material to see), and devs were around the corner for any questions - but in my experience, JSX did not appear to be relevant, not at all.
The only advantage jsx does have IME is that it enables copy-pasting real html (sometimes with minor alterations) into your source, and that's a mundane but constant minor boon. All the examples on the net are in html; and if e.g. you use browser dev tools to rearrange a page to look like you want it you can easily copy-paste that back into the source. I don't think that advantage is worth putting up with JSX for, but it's not irrelevant either.
I'm primarily a back-end dev with a bit of HTML+JS xp, and I had zero issues with JSX when I decided to use React for a small project. I didn't find JSX confusing at all, it took me about 10 mins to understand the syntax fully and the error handling was very explicit. I'm not experienced at JS frameworks (have used Knockout and that's about it) and I'm certainly not from a front-end or designer background, much the opposite actually.
What really bothered me at the time was that my code was messy and I was struggling to properly wire up the React components with my data model - thankfully I since discovered Flux and then Redux :)
div
className: "greeting"
"Hello, world!"
As you pointed out, the biggest problem with JSX is not that it isn't JS, it's that it isn't HTML. It's a leaky abstraction. Camel casing is only the most obvious problem, things like className and htmlFor are more insidious.So as soon as a developer realizes that it's just sugar over JS, they are in a world of trouble, invariably trying to stick an if-else into it. If everyone had enough grounding in language theory to tell them: "JSX is just a JS primary" all would be well, but alas, that's putting the cart before the horse.
Every single concept they hacked on to JS (immutable types, atom, declarative DSL, etc.) is a first class concept in CLJS - and it works beautifully even when building on top of their JS implementation - I feel sad they didn't just go "all in" on something like CLJS - they have more than enough resources to fix any implementation issues (ie. they have the resources to create a compiler that would generate code you would hand write with immutable.js and JSX - after all they are funding stuff like Flux and babel).
I understand why they didn't do it but it still feels so bad to see a hack in a place where a beautiful solution was just a step away.
(it's a joke)
Plumatic Schema [1] goes a long way towards narrowing that gap though and I cannot recommend it enough. Whether it goes far enough in terms of safety is certainly a matter of project type/size and personal preference, but to me, for my kind of work so far it does and they'll take away my ClojureScript when they pry it from my cold, dead hands. :)
Also (and slightly off-topic) the combination of clairvoyant + re-frame-tracer [2][3] (+[4] for some minor, so far mostly React Native-relevant additions) should be way more popular than it seems to be. It's definitely one of the most important tools in my toolbox and completely changed the way I approach debugging.
[1]: https://github.com/plumatic/schema [2]: https://clojars.org/day8/re-frame-tracer [3]: https://clojars.org/gnl/re-frame-tracer [4]: https://clojars.org/gnl/clairvoyant
At least for backend stuff, this is no worse than Clojure.
Give it a try :) Ping me if you have any questions.
Please take a look at the draft JSX spec [0] for details.
For a deep dive you'll want to read resources about parsing. To name one article that came up recently on HN, take a look at "Why Parsing Tools are Hard" [0].
[0]: http://blog.reverberate.org/2013/09/ll-and-lr-in-context-why...
Here is some of my Coffeescript render function, it is much more elegant than the equivalent JSX.
render: -> div className: "btn-group" role: "group" style: width: '100%'
for option in @props.options
label
key: option.value
className: @buttonClass @state.selected == option.value, option.bsColor
style:
minWidth: (100 / @props.options.length) + '%'
input
type: 'radio'
required: true
name: @props.name
value: option.value
checked: @state.selected == option.value
readOnly: false
onClick: @handleClick
"data-key": option.value
option.labelAnd the best parts are already here in es2015.
As the view counter started to exceed my expectations I thought there would be a fair amount of negative feedback. I was surprised that there wasn't much. Turns out that it's all here on HN! :P
First off, I can't believe all of you actually read that. You have both my sympathy and thanks. Even more thanks for commenting on it.
I want to address a few of the points brought up in the comments.
1| Yes the title is click bait. The title is the initial hook to the reader (and often the only thing you'll see before deciding to check it out). So by definition it is click bait lol It is also true.
2| The post wasn't intended to say JSX is bad or that you should use hyperscript (although I do think you should try it). It is an account of my decision to investigate hyperscript and some reasons why I chose to stick with it.
Each team and project is different and I am not so assured of my opinion to say that you should use hyperscript. I've seen some who genuinely prefer React.createElement. I've seen react-jade also brought up today. If there is a view abstraction that you like better then you should use it.
3| Yeah, the argument I present for why I implemented hyperscript may seem rather thin. For my team, however, it was not.
4| Despite the fact that we often talk about React and JSX in the same sentence they are not synonymous (see the "use the one you like" argument above). JSX does take some setting up to use. And you'd be surprised how often I field questions about the JSX transformer even though it was deprecated nearly a year ago...
5| The RTFM argument. If you knew the developers on my team they could tell you that I tell them to RTFM several times a day. I think it is very important for them to consult the docs whenever they have a question instead of me. That being said, I'd rather them RTFM about immutable-js or functional combinators than view syntax.
If you've got more heat lay it on :)
1| Don't let anyone bother you about headlines that attract readers and healthy conversation. Despite the romantic notions we may harbor about writing, it is an attention game for most who do it. Good headlines are a part of that game.
Kudos on handling the unexpected attention well :).
If I can double down on the mistake though, I'd be concerned if someone who didn't feel like learning how JSX works tried to dive into immmutables and combinators :D.
Thanks for react-hyperscript-helpers! Feels like react-native in a good way.
Haha, fair enough. Something that I didn't mention but I suppose bears noting, I have, not so secretly, been moving the organization I work for towards elm. hyperscript is much more akin to elm-html than JSX is, and is one of the "comfort level" stepping stones in that effort (along with immutable data structures, combinators, pure functions, etc). While the things I mention in the article were my primary motivators, I'd be lying if I said the above wasn't a factor too.
Thanks!
I wasn't a fan when I started, but now I love it to bits.
And the context switch has not proved to be a problem for me, but I'm sympathetic to the argument.
</2cents>
It's arguably a small package that you could just rewrite if things go wrong, but is it a smart idea to base any project on semi-abandoned code?
I swear half of the gulp eco-system is just that - half-abandoned, half-working little cute plugins that someone did because someone else's plugin, even though 99% identical, didn't do the one thing they wanted, so they wrote their own and then abandoned it, instead of maybe contributing to the other one. Sometimes, web development frameworks and libraries just feel like a giant software ghetto - a giant web of dependencies that someone combined into something with little thought given to long-term maintainability.
One of my team members refuses to incorporate a dependency that is by "some guy" and hasn't had any commit activity in the last month.
As an aside, we recently moved from Nunjucks templates to React / JSX at work and the frontend team couldn't be more pleased. Components reflect improvements made to them across the board and provide a happy medium between designer and JS dev. I have also found a lot of power in refs by implementing superclass functions that provide reusable logic for elements based on the key of the ref when certain functions are implemented on the corresponding component. This can be used for state persistence in forms, analytics or anything else the developer imagines.
Context switching has not been an issue but all of our frontend devs also do work on the backend. This may be an issue to consider for teams that don't embrace cross disciplinary roles.
That's a pretty nasty comment to make about anyone in this industry over a simple for loop.
<div>
{for (var x=0;x<10;x++) {
<div/>
}}
<div>
Not a templated component like that. That said, I have created repeater components and the like before, largely because JSX is so friendly that more design-minded people can use it very easily.EDIT: turns out that doesn't actually work, ha. I've never written JSX that way.
<div>
{[0,1,2,3].map((i) => {
<div/>
}}
<div>
on the other hand... <ul>
{this.listItems(items)}
</ul>
Then, within a function implemented on the same component: listItems: function(items) {
items.map((item) => {
return <li>{item.name}</li>
});
}https://developer.mozilla.org/en/docs/Web/JavaScript/Referen...
To be more constructive, I believe an understanding of when to use the right tool for the right job is paramount to a good software developer. JSX nodes are suitable for representing UI components but certainly not control statements such as a for loop.
Hyperscript seems like a "reasonable alternative" to JSX. I won't say "better" because you're trading <angle brackets> for `h([ , ])` symbols that also contribute to line noise. And other common pain points like "you can't put an `if` block inside your markup" still persists.
disclaimer: only read the README, didn't try actually using hyperscript.
If we want to go with the code route then the DOM as code is actually really clean with Coffeescript.
Elm is interesting but I don't like having to do [] (empty array) when there are no attributes or [] for the children when there are obviously no children (hr, br, img, etc).
I've yet to figure out if the run-time performance hit is reasonable, but I vastly prefer the syntax to either JSX or hyperscript (I previously wrote a hyperscript-like library as well, and have used it for several months)
A more important point is the handlebars. So, handlebars implys block in javascript but what is actually happening is the context is evaluated and passed to the component. Kindof how parenthesis work
(A || b).property(array.sort(compareFactory())
The fact we use handlebars when the text inside is actually evaulated how parenthisis work probably enables this sort of confusion. The reality is handlebars is for the angular/mustache crowd and to ensure they feel at home. But in parenthisis would build on exisisting knowledge of how js works
<div count={count?true:false} />
<div count=(count?true:false) />
{ console.log(123); }compare
<div>
console.log(123)
</div>
with <div>
{ console.log(123) }
</div>
The first outputs a div with the text "console.log(123)" inside. The second logs "123" and outputs an empty div (since console.log returns undefined). React.createElement(div, { count: count?true:false })
not, as your comment implies, React.createElement(div, { count: true })But I've never seen anyone, not even the most junior, backend-only developer touching React for the first time, have any issues with it for more than 4-5 minutes. ESLint catches any mistake they make.
The only real argument, and it is a valid one, is that Babel does not use shorthands in the output, so it's a trainwreck to read. If that was the primary argument, I could get it. Though then IMO the solution would just be a better Babel plugin for development.
Why would you ever do that instead of having the logic in the component itself?
Sometimes you just don't want to RTFM, and so you get to enjoy the standards problem[2] rather than learning someone else's tool. Sometimes you just have a lot of spare time and want to re-implement something as a learning experience. But it's a good idea to acknowledge the technical merits of those who've come before when you want to go down that route - JSX is a _well done_ project. If you don't learn from it's good parts (familiarity, ease of use, prolific tooling), as well as the bad you feel you see, you don't get anywhere. The author became familiar with JSX to the point where his perspective of its benefits and flaws shifted - after using it for a long time you can forget its benefits until you no longer have them.
For example, I would argue that the contextual switching the author complains about is a _good_ thing - I find the extra hesitation helps you create boundaries and keep unneeded code out of your views.
If you can't tell, I enjoy JSX tremendously and I'd like to use it or borrow from it extensively outside of React.
/** @jsx ExampleDOM */
As the first line in your Javascript source file. This indicates to the transpiler to convert statements of the form <example name="Wesley" age={15}>
<Message text="hello"/>
<Message text="world"/>
</example>
into ExampleDOM('example', { name: 'Wesley', age: 15 },
ExampleDOM(Message, { text: 'hello'}),
ExampleDOM(Message, { text: 'world })
)
where you implement ExampleDom as function ExampleDOM(element_or_component, attributes, ...children) {
}
Note that because 'example' starts with a lowercase character, it is transpiled into a string first-argument to the ExampleDOM function. If it starts with an Uppercase letter (i.e. 'Message' above) it is interpreted as an in-scope Javascript variable.We've had really good results using JSX outside of the core react library. For example, we've built a "React.js for Excel" that lets us easily create rich Excel workbooks:
<worksheet
clear
protect
flow="column"
name={`Bespoke - ${network.shortname} - WACC`}
tabColor={theme.bespokeBlue}
displayGridlines={false}
style={worksheetStyle}>
<PageLayout
title={`${network.name} Cost-of-Capital Worksheet`}
lastUpdated={new Date()}>
<UpdatedWACCEstimates network={network} determination={determination}/>
<WACCForecast network={network} forecast={forecast}/>
</PageLayout>
</worksheet>
Which looks a lot like React.js and behaves almost exactly the same, but it's targeting the Excel COM Object model rather than the HTML DOM.This becomes even better when using a TypeScript capable editor with TSX, creating classes for the components and taking advantage of full autocomplete and syntax checking from your editor. Your code ends up pretty readable, composable and error free.
Mixing HTML and server side code may let you do toy projects quickly, but in the real world it's a great recipe for building an unmaintainable, undifferentiated, monolithic mess.
I work on very "functionality-oriented" applications; no dedicated designers here. Having a split between JS view code (example, in the form of Backbone views) and template code is just frustrating to deal with. React addresses the issue by putting the relevant pieces of view code together. The React code should be separate from other code types (whatever you would call it: models, business logic etc.), but that's just like what we are trying to solve with separating server-side + HTML.
I still think however, React is controversial. I would be considerate when deciding to use it, because I just don't think it is that important for many applications.
That said I really don't find any of the authors arguments particularly persuasive. I work with many inexperienced JS devs and haven't seen them struggle with these issues in JSX. Not to discount the authors experiences, it just seems this article could have been more about highlighting the library, rather than creating highly contrived seeming examples of why JSX is bad. I also agree with some of the others, that the advantage of JSX mostly comes in working with designers and people more familiar with HTML than JS.
React.DOM.ul() works as it always did. Even if we change that (since it's kinda silly to ship down a big list of tags that we don't otherwise need), you can also do
var ul = React.createFactory('ul');
and then ul(). No big deal.
[B] requires the first argument always to be props, so most of the time for empty props, people end up always giving `{}` or `null` as the first arg. In [A] they are optional. In JSX if you don't have props you don't need to provide any "empty props" object.
In [A], children are always an array, while in [B] sometimes a single-child parent only accepts that child as last argument, instead of an array with one child. Otherwise it's a runtime error or warning. This special case treatment is only visible when using [B], but transparent when using JSX.
In [A], the first (optional) argument can be a CSS selector to declare the classnames and id. In [B] you have to give it explicitly as props.
All this indicates that while React supports a non-JSX workflow, [B] is way less practical than JSX, probably because Facebook itself uses JSX extensively, and supporting non-JSX workflow was an afterthought when releasing React to the public.
I find JSX, at least within context of react-native is very useful.
I specifically like being able to have this 'duality' of a view for a Component.
JSX allows a custom component to viewed by outside as first-class citizen of an HTML mark up. But within the component -- it is a class with members, Eiffel-like preconditions for construction, and explicitly managed state.
I think React-folks got the separation between Presenters and Interactors exactly right.
I would not mind even more features where the state management relies on channels that are can contain Parent, children, and may be even 'peer' events. (something like clojurescript's CoreAsynch for the above 3 categories of events affecting states for a given component).
In the same line, breaking things into components is best achieved, in my opinion, using web components. The syntax is a little muddy, due to all the html legacy cruft. But I find it better than the alternatives, for example react components. With web components, the great thing is that any styles and javascript functionality is scoped to the component. That allows for better separation of concerns in separated components. This is specially useful when you have components with functional styles: animations, transitions, etc.
After componetization is solved by web components, the problems with html in html boils down to mostly two things: generating multiple elements from some data, or setting data in elements based on some other data. For these things I prefer the syntax style of data binding and "repeaters". My favorite is polymer(https://www.polymer-project.org/1.0/). Example:
<el-container id="listbox">
<el-list-items itemsdata="{{model.itemlist}}"></el-list-items>
</el-container>
And the concern of repeating multiple elements is trapped in a component. In the example above, in <el-list-items>. In general, when using this technique, data binding must not be abused, or the view becomes a mess.Personally I like JSX. It's nice having a special syntax that your editor and linter [1] can understand. And if you are part of the stateless/minimal-logic component camp then most of your components will look more like HTML/JSX with a little bit of JS interspersed than vice-versa.
[1] https://github.com/yannickcr/eslint-plugin-react#jsx-specifi...
Medium has become the analog to Tumblr posts for opinionated engineers to whine about things that don't really impact development in ways that matter.
Really all this developer had to do was talk about Hyperscript in a positive way and I would have found this post interesting instead of rolling my eyes paragraph after paragraph. Oh poor you and your angle brackets, such a burden! Putting HTML directly into my JavaScript is awesome and I never want to go back to separate template files ever again. It's wonderful and results in great code that works well, is readable, and is easy to test.
This post spends quite a bit talking about beginners who are learning Javascript, React, and JSX all at once. Of course they aren't going to get it right immediately, if they didn't get tripped up on JSX they'd get tripped up on something else. "Beginners don't get it" might be the weakest argument I've heard so far.
Pick languages/frameworks that will produce easily maintainable code and will survive naturally after your departure from a company. New developers have a learning curve no matter what. The steeper you make that curve, the more danger you put your codebase in and the more likely you are to set them up to fail.
But since when have we been any good at identifying future needs or identifying maintainable code? Just be consistent, try to at least leave SOME documentation for the next guy, and don't be actively malicious.
Note that the author isn't suggesting a return to separate template pages. He is suggesting a system for creating React elements that uses simple functions and JavaScript syntax rather than the custom syntax of JSX.
"React is, in my opinion, the premier way to build big, fast Web apps with JavaScript."
Nowhere in the documentation does it stress that it's easy to learn or ideal for beginners. If you don't know Javascript, writing React applications (or any application, really) is going to be painful. Full stop. JSX adds cognitive load when writing code, but reduces cognitive load when comparing the DOM to the component that created it. Given the amount of time I spent debugging and refactoring, I'm happy to use JSX.
Maybe it's the article's title that has understandably rankled some people by seemingly maligning JSX. However, I think it's a very valid concern to have when ramping up a team that's unfamiliar with JS and React.
I'm not in the situation of ramping up a team unfamiliar as the author was. But it sounds like he was experienced with JS and React himself. Or are you suggesting he should replace his team with people more familiar with JS+React?
I think of it as a child of - XML + JS.
I am waiting for JSS - CSS + JS, for the styling part.
Radium [1] is a promising start.
why are web-developers so damned clever? do we really need to do all of this to ourselves?
the web is just a port, a protocol, and a model for interaction, underneath it all.
why on earth can we not live with the existing web, and move on towards inventing other spaces?
a browser is just a shitty sandboxed OS with a declarative markup renderer. there's nothing to stop anyone from making a different client-side x-terminal... (as that's what people are trying to turn the web into, apparently)
joke aside, I think JSX does a great job to reduce the cognitive load, bridging codes as representation and its result.
This seems plenty easy to read and write and has the benefit that it's pure JS and doesn't need to be compiled during development:
const listItem = item => `<li><a href="${item.link}">${item.name}</a></li>`
const listComponent = items => `<ul>${items.map(listItem).join("")}</ul>`JSX >>>> ES6 template strings
Unfortunately, as much as I want to learn React.js, there was too much context switching.
The only reason I'm persisting is because of react native. As soon as somebody comes up with a better way I'm ditching react
back to my good ol' jQuery
2) The separation of concerns argument is completely invalid. They aren't separate concerns, they are separate languages.
React is a view engine; everything done in react is to construct and maintain the view.
Seriously: Separation of Concerns is solved. Yes, you were once far ahead of the pack. But at some point _everybody got it_. It no longer needs a (cumbersome) technical solution because we solved it with education, and developers have been highly disciplines since almost the late 90ies.
It's nothing more than a DSL for a templating language that finally puts the template for a component where it belongs -- along with the presentation logic.