Hacker News new | ask | show | jobs
by fleshweasel 3419 days ago
One of the biggest reasons I favor React is that it's much easier to add a templating language to a programming language (i.e. JSX) than the other way around. Every construct for making decisions based on your data, traversing your data, etc. is more cumbersome and harder to validate in handlebars or whatever identical looking templating language the community came up with this week.

I also am strongly against string references to model properties in your template. Again, it's much better to use tools that provide some static validation of what you're doing.

Give me React with TypeScript to help me make sure I'm passing around what I said I'm expecting to receive at each point as features are changed and added, and I'll be in business.

Honestly, I use React in spite of my opinion of Facebook.

10 comments

JSX frustrates me. When did we suddenly start thinking <> syntax was desirable again? When did the complexity of combining markup syntax and a programming language become a good idea? Why are we forcing this crazy complexity into every language and every IDE / code editor out there?

I much prefer react with standard functions e.g.

    var element = DOM.p({id : "thing"}, DOM.div(), DOM.div());
You can use an API like this in every language without any hacks. It doesn't hurt readability or productivity and it has normal expression evaluation semantics. JSX isn't syntactic sugar, its a gross "syntactic artificial flavour" because it doesn't make the syntax easier, it just makes it look something a bit like HTML but with dozens of subtle differences e.g. attribute names, attributes values, tag closing rules, special extensions etc.
Frankly, yes it does hurt readability. I used to have your mindset and you're making the assumption that what looks okay when creating one single element will look fine when nesting dozens (which react excels at).

JSX is well defined and does not support any of HTML's looseness. It's predictable. It makes the code easier to follow. And if you don't want to use it, you don't have to. I see no issue.

> will look fine when nesting dozens

Nesting dozens of items is fine. That single line was more of an HN comment format limitation. This might be a better judge of readability:

C#

http://imgur.com/a/nVWdC

JSX

http://imgur.com/a/qwAfD

You may prefer one or the other but most would admit they are pretty similar its just that the former hasn't needed an entire new language inlined into it. Given JSX has all its angle brackets, end tags and escaping expressions with {}, it can actually be more verbose.

I'm a C# guy and even I would say the JSX is far more readable there. I'm sure there's a law somewhere that says the less abstraction the better, that can be applied in this case.
I don't mind if people prefer JSX its just a shocking cost - rewriting language ASTs, build tools and IDEs for something that rhymes with html but is really only a couple of characters away from standard language constructs.

> I'm sure there's a law somewhere that says the less abstraction the better, that can be applied in this case

JSX is literally an extra level of abstraction. You are not writing html but calling a function to create a data structure element and JSX totally obfuscates that. I pity poor programming newbies trying to understand what JSX is actually doing "so you are telling me <div> is a function...but?".

In the functional form its just your normal language, nothing is disguised, everyone can see what it is doing and no post-processing magic is required e.g.

    public class DOM
    {
        public static IElement div(object attributes, params IElement[] children) 
        {
            return new Element(...);
        }
    }
I agree with everything you say, except the "shocking cost" part. Its all a matter of perspective.

You would have to write the transpiler anyway, since on a larger team if you're working with a designer, you would probably get HTML from them and soon get tired of manually translating it to function calls.

I'd bet this is how JSX got started in the first place.

In my experience, using a programming syntax for markup actually turns into a PITA. My only experience is HTML + Silverlight, but in both instances doing it in markup over code is almost always easier/quicker/simpler to read/less TLOC.
I agree that I wouldn't change your current tooling, as the cost isn't worth it. JSX isn't that great. But even though it turns that HTML into function calls, there is still an expectation of how it will work: i.e. those functions will still produce the specified html. At the end of the day, writing a layout in html is so much more intuitive than using function calls. Makes me think of how MS introduced the XAML language when they created WPF, making it far nicer to build UIs out of code than in winforms.
> That single line was more of an HN comment format limitation.

What limitation are you talking about?

    var element = DOM.p(
        {id : "thing"},
        DOM.div(),
        DOM.div()
    );
(The JSX one returns undefined)
I will never understand why people think JSX style processing is a good idea. It's hiding what's actually happening, at no benefit (or very little benefit). At least with the former (C#) I can neatly build things up, reuse those components, instead of passing some monstrosity around.
I don't understand this. You could build up the template using jsx exactly like you could otherwise. For instance, I could put that in a variable and then use it in another template via {}
You could, but it's unintuitive (in my opinion) to do so -- which was the parent's comment larger point. You're not doing anything different, and to an extent the latter is actually lying about what's going on (you're not writing HTML). I also lose a certain level of tooling by doing it the JSX way. Why try to mask what you're doing? Why make it harder for your tools to help you out?
The time I spent fixing logic and layout bugs on several build-a-dom projects has taught me this. For the same reason using CSS Selectors to crawl the DOM is superior. When it doesn't work, how hard is it to spot the bug? If you're working on the front end you need to look things up roughly the same way for style and behavior, and emit them roughly the way the browser will see them when it's time to look them up.

And yet I'm still in the anti JSX camp. I think it has something to do the gear switching that comes with opening up the mixing of data and logic but I can't articulate it farther than that,

Your brain can only juggle a handful of bits of data at a time. If you see someone doing something that looks like this doesn't apply to them, it's most likely because they've memorized the code. And to memorize code, that means it can't change much or very often. Which makes them dangerous. They have a bias toward maintaining the status quo, no matter how awful it is. Don't be that person.

Many people find deeply nested tree structures hard to read when you need to mentally balance a bunch of parentheses. The inability for s-expression languages to gain significant traction with lay programmers is evidence of this.
People who use Lispy languages do _not_ balance parenthesis mentally. In fact they completely ignore parenthesis and go only by indentation. Parenthesis disappear when you are at certain level of proficiency.
Yep, but most people don't get to that level of proficiency.
> When did the complexity of combining markup syntax and a programming language become a good idea?

When unobtrusive javascript became a thing.

> As an industry, we’ve already decided: HTML and JavaScript belong together.

https://medium.com/@housecor/react-s-jsx-the-other-side-of-t...

having played with clojure i really fell in love with hiccup syntax:

    var element = hiccup [p {id: "thing"}
                          [div "first"]
                          [div "second"]]
https://github.com/lantiga/react.hiccup
Yeah hiccup syntax is my favorite as well. JSX is mentally the same thing for me except I read "HTML" faster than data structures if that makes sense.

I wonder if Hiccup was the first one to introduce this syntax? I never bothered to check but I always thought the JSX inventors might have been inspired by it.

I somewhat agree, but a little inconvenience comes when you have to insert HTML that you got from somebody else, like from a design template or an ad or analytics code. Sure you can convert it by hand or with an editor extension but then you are just doing the same as JSX, or you can insert it as a string but then it becomes inconsistent.
Don't use it! I just use hyperscript and functions. Works great.
point of jsx is to make react more intuitive to non-programmers
If JSX is embedded in a codebase, what is the value of that? Let me clarify a bit. What is the value in creating a limited tool optimized for neophytes that will be used extensively by experienced professionals, who would be better served by flexibility?
I had a lot of success back in 2013/14 by having our outsourced graphic designer directly modify JSX files in our codebase. He picked up just enough javascript to figure it out. I just told him where the file was or set up a test harness and he delivered pull requests against our actual codebase.
I think you are being a bit overdramatic about JSX. There was zero learning curve -- except for a few errors initially when using class instead of className...

The argument that DOM.div() is more readable than <div/> is honestly hilarious to me. Any non-trivial tag structure will be unnecessarily complicated through the API. Especially when you can just write it almost exactly how it's going to look when it becomes HTML in JSX.

DOM.div() vs <div/> seems like a bad example. IMHO, when you get an element with tons of event handlers and conditional classes, or when you have a deep chain of ternaries that's where angled bracket syntax starts to become unwieldy.

The className thing is a big deal too, in my opinion. Preact and Mithril do what you would expect, and perf doesn't suffer, so why can't React/JSX normalize it as well?

If you have deep chains of ternarys, that's a symptom that you should be splitting your rendering code into another function or component. This would be true regardless or what approach you are taking to templatihg.

That's one thing I really appreciate about jsx: the lack of rich template code syntax makes it glaringly obvious when your template code is doing too much and should be refactored. It does a really good job of keeping your logic in javascript and out of your template.

Refactoring into functions/components doesn't magically make a complex ternary tree go away. It helps the body of each branch be less noisy but the ternary tree will still be there.

You're talking about taking something like `foo && bar || baz && quux` and turning it into `isSomeCondition()`, but that's a pretty obvious refactor in any templating system.

I'm talking about things like

    return (
      <div>{
        x.type === 'foo' ? <Something/> :
        x.type === 'bar' ? (
          <div>
            <h2>More stuff</h2>
            <Another data={x.data}/>
          </div>
        ) :
        x.type === 'baz' ? <Another data="baz"/> : null
      }</div>
    )
At this point, I think it's perfectly valid to have the opinion that JSX isn't helping much, since the JS-to-HTML ratio in this case is relatively high.

Refactoring would just make it more difficult to mentally piece things back together given you would end up with sparse component instantiations scattered amidst otherwise-procedural js code, as opposed to the more ideal single-root, declarative virtual dom tree.

Without understanding what x.type is, I'd be inclined to write that without any ternary operator at all using plain old if statements with each returning JSX markup. I try to keep logic in JSX to simple ternary operators and loops at most. JSX is really just shorthand for DOM.div() for me. I imagine the code structure looks pretty similar to actually using DOM.div though. I'm not seeing how programmatically creating markup with DOM.div results in significantly different code, although if you have some good examples I'd love to understand them better.
Ternary operators should never be nested, whether you're using JSX or not. If you have that many conditionals you should use variables and/or decompose the optional pieces into sub-components. Pretty much any time you have a tag that has a huge number of attributes, it's a smell that you need to decompose something.

Variable assignment is the simplest answer, which takes advantage of the fact that null or undefined values are ignored in JSX:

    const Dashboard = (props) => {
      let avatar;
      if (props.user) avatar = <Avatar user={props.user} />;
      return (
        <div>
          {avatar}
          ...some other content...
        </div>
      );
    };
Regarding class vs. className: class is a reserved word in JS. It's not really a perf thing, it's the fact that JSX was intended as a very simple transform. If JSX used class instead of className, the transpiler would need to be contextual since "class" would sometimes mean "css class" and sometimes "JavaScript class". The baseline complexity for the parser would be higher and could lead to all sorts of complexity. Rather than deal with that the React team avoided the problem by using className instead, keeping things simple.
I think this proves lhorie's point. Markup syntax is dominated by code when you are building complex dynamic apps instead of static documents. What do you really gain by putting angle brackets around Avatar instead of calling a function?

FWIW I believe new react devs are slow to realise they can use local variables like this because JSX looks like it is doing string templating instead of object instantiation.

The example I gave was simplistic, but the value of JSX is the ability to easily nest elements. For instance, let's take my previous example and say we're creating a profile link:

    const Dashboard = (props) => {
      const {user} = props;
      let link;
      if (user) {
        link = (
          <a href="...">
            <Avatar user={user} />
            <span>{user.name}</span>
          </a>
        );
      }
      return (
        <div>
          {link}
          ...some other content...
        </div>
      );
    };
If you want, you could create a `createProfileLink()` function, or you could create a `ProfileLink` component, or you could keep it as a variable in the `render()` function. This flexibility is what makes JSX powerful.

    > Regarding class vs. className: class is a reserved word
    > in JS. It's not really a perf thing, it's the fact that
    > JSX was intended as a very simple transform. If JSX used
    > class instead of className, the transpiler would need to
    > be contextual since "class" would sometimes mean "css
    > class" and sometimes "JavaScript class".
I don't think React should have used `class` instead of `className`, but this isn't the reason.

    <foo className="bar" />
compiles to

    React.createElement("foo", { className: "bar" });
It could have just as easily have been that

    <foo class="bar" />
compiles to

    React.createElement("foo", { 'class': "bar" });
as far as JSX is concerned (or even without the quotes in an ES5 world).
The output isn't the problem; it's that "class" is also a keyword in the JSX input. I admit, though, I'm not intimately familiar with the JSX transpiler and am just guessing as to their motives.
I'm actually fine w/ JSX being "dumb" and just translating `class` to `class`, but when used in conjunction w/ React, the end result is that the JSX "markup" has a lot of traps that simply don't exist in similar libraries like Mithril.

`className` isn't the only offender. `onClick` and `readOnly` are other notorious one. And then there's stuff like `xlinkHref`, because it's not like anyone ever imports SVG from external tools.

className was named that to avoid conflict with the JS class syntax originally I believe, since JSX is inline - they probably could put in the work to change it at this point, but it seems like a minimally beneficial change but massively disruptive at this point.
It was named that to match the DOM api[0], which React does whenever possible. The DOM api is probably named for the reason you state.

[0]: https://developer.mozilla.org/en-US/docs/Web/API/Element/cla...

And the reason why the DOM API uses className is: class is a reserved keyword in JavaScript for a long time.
There's also stuff like onClick, readOnly, xlinkHref... I would guess that a healthy number of React-related google searches are related to these gotchas
Have you tried Elm? It is strongly typed and it uses function to represent html elements and attributes, which end up looking a lot like JSX.
Haven't had the chance to try it myself but I have read quite a bit and I like what I see, particularly the high quality error messages in the compiler. However, I think I'd have a hard time getting my team on board with it as we use Visual Studio for the bulk of our development, and we would need to learn to work with the JavaScript interop APIs to do things like try Elm out for a single new feature on a page.
I've personally been impressed with learning Mithril over React. Surprisingly easy to learn for people coming from React and super fast. XHR and routing are included. You can use JSX but hyperscript (pure JS that has no compilation step) is favored for markup. Add in some Aphrodite for inline styling your components, Redux for state management and you have a pretty robust, blazing fast framework that is sufficient for many modern application without all the package bloat.
In support of this argument -

The HTML snippet embedded in `let titleView = "<h1>Hello</h1>"` can only be parsed as a string. This means no tooling support - no linting, no tags that autoclose, no code formatting. But if you have a distinct syntax for XML, the parser can clearly figure out what the strings are, and what the tags are.

First class support for XML is, after using JSX, just so obvious in hindsight if you're building anything to do with the web.

Scala introduced first-class support for XML through a DSL a decade ago. I believe the feature has been phased out because it was useless. I've personally never found it useful either.
When a react component tree has more than 3 level height, react component's lifecycle callbacks start getting crazy unmanageable.

Mounting, unmounting, rendering, props receiving, updating etc, these callbacks' calling orders open to bad rendering practice(e.g. unnecessary render, unexpected calls), that's why people avoid putting logics in there. It claims to be self-contained but parent-child communication breaks it in several ways, I am not a big fan of HOC.

People claim the simple of "just a view layer" of react, I don't think so. I haven't tried vuejs, but it seems like it takes care of most rendering callbacks/component communication seamlessly.

> It claims to be self-contained but parent-child communication breaks it in several ways

I think you'll find that most react developers advise against doing parent-child communication in react components for all but the simplest cases. Does it involve writing higher order components? Probably. Curious, why aren't you a big fan of them?

Higher order components to me is a hacky technique and mostly seen as a monkey patch to the limitation of lower component.

A concrete example is responsive table components with the help of HOC, says `react-dimensions` (sorry author, I have to mention here but there is nothing specifically wrong with it), why do I need it as a separate component? Oh flexibility and reusability but when I tried wrapping 2 or 3 table libraries with it, it sucks at rendering on desktop, even worse on mobile! I gave up on performance issue. Ah that doesn't mean the HOC technique itself is bad, but from my experience it is.

I know what you mean with regard to event handlers being passed down to children and children of children and so on and the complexity that can bring. I haven't used redux, but I understand it as being an attempt to simplify that kind of problem.

I haven't written any higher order components myself, unless you consider parameterizing event handlers in props to be higher order.

Composing pure functions makes more sense, passing function as argument in functional languages is way better than having the higher order component thing. Sure javascript can do that but in the react world, "component" thing go with you everywhere regardless of presentation or dumbest components.
This.

"Good view layer code means that templates should be as declarative as possible, NOT that the view layer as a whole should avoid procedural logic altogether." - https://lhorie.github.io/mithril-blog/getting-over-a-fear-of...

There is the choice of preact[1], that has a very similar api, is more lightweight and even has a compatibility layer for the few react packages that need it.

[1]: https://github.com/developit/preact

also in vue 2.0 you can use jsx e hyperscript
Why would you? React is a tool. The fact that FB doesn't use the tool correctly shouldn't reflect negatively on the tool. That "honor" goes to the product.
You do know that Vue support jsx. Just not react's jsx.