Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

The arguments against JSX and React requiring many small components are very surface level and sound like "we couldn't figure out how to make it work for us so it must be impossible".

1. This was mentioned already, but, yes, you can use ternaries and boolean logic for simple conditionals (loggedIn && <a>Logout</a> || <a>Login</a>)

2. When you need more markup, put them in an if-else statement in the same render function.

  render()
    if (loggedIn) {
      var login = <a>Logout</a>
    else
      var login = <form onSubmit={ ... } />
    

    return <div>
      { login }
    </div>
3. With SFC it's trivial to split these out into new components. You can even use bound methods to reuse the component state and props.

  class Navbar {
    LoginForm = () => {
      if (this.state.loggedIn) { ... } else { ... }
    }

    render() {
      const {LoginForm} = this
      return <div>
        <LoginForm />
      </div>
    }
  }
4. And finally, what stops you from creating a custom component that works like this?

  render() {
    return <If cond={ this.state.loggedIn }>
      <Then>Hello { this.state.userName }</Then>
      <Else>Please log in</Else>
    </If>
  }
There's a continuum of ways you can structure your code, it just takes some experimentation to find what works for you.

After working with Angular templates for a long time and then switching to JSX, I'm never going back to having my markup in a string blob with magical attributes that make it do stuff.



Thank you for fixing the misleading information from this article.

I would add:

1."now you have to create 10 functions to get input from 10 inputs".

Or you can learn JavaScript:

  handleChange(event) {
    this.setState({ [event.target.name]: event.target.value })
  }
2. "Redux sounds like a synonym of verbosity, as well."

Nobody forces you to use Redux.

https://medium.com/@dan_abramov/you-might-not-need-redux-be4...


> [event.target.name]: event.target.value

Dumb question but I've never seen this syntax before. What does it do or what is it called? (The brackets)


Computed property names. Any expression whose value can convert to a string or symbol will work. ES6 added them:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...


Excellent, thanks!


It's not a dumb question at all. It's relatively new, and I would implore the originator of that comment to take a different tone. It requires a newer browser or some sort of transpilation step. (You're probably already using one if you're using React)

Most of the React community has forged forward with ES6/ES2015, so learning that is definitely a part of the process.


He may have chosen to use newer syntax, but the same pattern can be used without computed keys with only a tiny more code:

  var stateUpdate = {}
  stateUpdate[event.target.name] = event.target.value;
  this.setState=(stateUpdate);
I don't think there was anything necessarily wrong with his tone as he was addressing the tone of the original article.


Telling someone, "or maybe you should learn JavaScript" is kind a really jerky way of saying, "you don't know what you're doing". I do think it was a terrible way to share knowledge. Yet it was an excellent way to say, "I know more than you".


I agree it is rather combative, however it's also true. To claim that X pattern is a reason to not use a library when said pattern is actually an anti-pattern you've used because of lack of understanding is going to garner these kinds of reactions.


This is exactly what I've been using for a while now, and was hoping something better already existed in ES6. Great to know there is!

FWIW, this is supported in the newest Chrome as well.


> And finally, what stops you from creating a custom component that works like this?

I wondered what the issue was myself, so I actually implemented that pattern in a codepen, then looked at the compiled form of the JSX to Javascript.

The essential issue is that the value of a prop is always evaluated at runtime, regardless of if the prop is actually used. In the case of props.children this means that <Then> and <Else> are both evaluated, and thus rendered, and only one of them is actually used.

Thus you can't have conditionally rendering children, unless you've written them to be okay with failing at a render, with a blanket state---which is what most people are trying to avoid writing into their components, and simply want to conditionally render in a higher level component.


You can get around it with a Babel transform:

https://www.npmjs.com/package/jsx-control-statements

Disclosure: self-promotion. It's really frustrating that I see this React-is-crap-because-no-conditionals come up again and again but if you want them all it takes is an npm install and a line of babel config :(.


The article doesn't bash react, but it does say that Vue's ability to use conditionals is superior.


Wrapping them in methods is an easy way to fix that... but not sure if it is any cleaner.

    render() {
      return <If
        cond={ this.state.loggedIn }
        then={() => `Hello ${ this.state.userName }`}
        else={() => `Please log in` }
      />
    }


Or with an algebraic Maybe data type

  {this.state.user.case({
    some: user => `Hello ${ user.name }`
    none: () => `Please log in`
  })}
Or for async requests that are in progress, an algebraic 3-state type:

https://twitter.com/Tholle1234/status/804796967222202372


since then and else are going to be used inside an if component, you can use context to read condition, then not render at all if you don't need to (return null).


I think your comment just proves the point of the original post. Your examples are still not good enough for me in terms of syntax and real work with html guys (specifically, <If><Else> has some quirks). I've gone through these things, and the pain&negativity about Angular 1 which translates to negativity to all template engines was also mentioned in the post.


JSX is awesome. It's just JavaScript, you can do whatever you want...

return ( <Foo> { selected ? <Bar /> : null } </Foo> );

or

let children = []; if (selected) children.push(<Bar />); if (blah) children.push(<Blah />); return ( <Foo> { children } </Foo> );

or

const bar = selected ? <Bar /> : null; return ( <Foo> { bar } </Foo> );


Our Perl5 CGI.pm codebase used to look like that (html + logic). Fortunately we switched it over to Mojolicious and it became manageable. Not going back there thank you.


> and sound like "we couldn't figure out how to make it work for us so it must be impossible".

It sounded more just like "we couldn't figure out how to make it work for us", which is a perfectly plausible position.

The author just stated that React didn't work for them, not that it's "impossible to use React" as you are implying.

From the article:

> I guess this level of strictness and purity is something that may be useful when you have 1000 devs in your company [...] But most of companies have far smaller dev teams and other goals than Facebook.


Fair enough, but if they're going to write about their opinions and argue that "JSX sucks", they should at least be intimately familiar with it. Choosing lack of conditionals as the issue to focus on instead of any other problems templating in React has tells me that they're not.


After working with Angular templates for a long time and then switching to JSX, I'm never going back to having my markup in a string blob with magical attributes that make it do stuff.

why would you do this in Angular? i thought the whole point was to use html templates in separate .html files. as for "magical" attributes, angular2 moved away from that and is using mostly native html attributes. i.e. [disabled]="x" [hidden]="x" (click)="myfunc()". Can't imagine it being more intuitive than this.


JSX actually makes it more intuitive than that by having 0 reason for even needing to know when to use square brackets vs parenthses. It's simply curly braces and vanilla JS


this is a different statement than the sentence i responded to. square or round just indicates the direction of the binding. everything in angular is also vanilla js.


I think what he means is that control statements don't exist in JSX. You have to write Javascript to do if-statements, looping, etc.

In React, there is no 'direction' of binding---its all one way, just like in vanilla Javascript, and in fact no binding on anything except low level elements' like divs. Components only receive props, which do not do anything at all until you write code that reads them and runs operations based on their values.

Thus components are simply function calls (it's what they compile to anyways), and JSX is just a syntax to write functional code.


i don't see how sprinkling if-statements in your html is cleaner than "magical attributes" but thats just me :)


It's not just you...this has been a pretty big toss-up with MVC style frameworks and view libs. Does business logic belong in the template? Or does it belong in some sort of view controller? Mustache.js insists that all decisions should be made before data is sent to the template. Most other libs allow the template to make decisions. I don't think there's a definitive answer. I kinda lean on making easy decisions in Handlebars templates... or, since our new app is in React, JSX.


if statement is one of the most basic concepts of programming and is opposite to magic


True, but some would argue that its use is a mark of lacking taste - https://medium.com/@bartobri/applying-the-linus-tarvolds-goo...


Wait, square brackets/parens indicates data binding direction in vanilla js? Huh?


It's still just a giant string blob which is interpreted by Angular at runtime. Just because it's in a seperate file doesn't change this.

JSX, on the other hand, is Javascript function calls. You're writing JS to describe the UI.


To be fair - the reason Angular 2 moved away from that is largely due to the influence of React

That's not a bad thing of course.


When I first started using React, I was very concerned about the lack of template support for conditionals.

In practice, I've find that I now segregate heavy logic into it's own function, which ends up making my components very readable. The lack of first class support for conditionals as a part of JSX has forced me to encapsulate code better.

I would say the only trade-off I've noticed is I end up losing a little bit of DRY-ness here and there with some components having near identical functions. I think it's an acceptable trade off as long as functions are small.


When I see examples like this, it reminds me just how elegant & simple Mustache.js template can be:

  Mustache.render( "{{#loggedIn}}Hello{{userName}}{/loggedIn}}
   {{^loggedIn}}Please log in{{/loggedIn}}", state );


What exactly is elegant and simple about that? I feel like this kind of syntax would break down on more complex examples, is that not the case? What would it look like with multiple conditions (say something like A && B || C)?


What on earth does not break given more complex examples? That's a bit of a non-argument. The mustache example is a direct translation of the jsx example, so keep things in context. As for your multiple conditions question, what exactly is the point of that? All l see is code, no data, no markup. Completely irrelevant.


No need to get so defensive. I'm just curious how it holds up in more complex examples. I know how JSX does because you just use the same concepts you already know from JS. But Mustache seems to have its own custom syntax, so how well can it express more complex cases?

After all, we're not just displaying "Hello" or "Please log in" all day.


I simply responded in kind. Notice the difference in tone from your first response, and this one.

To answer you question, you use JS! Or PHP! Or any of the other 2 dozen languages Mustache supports. Mustache is all about logic-less templates, which by definition assumes the logic is being written elsewhere. Edited my example to make that clearer.

EDIT:

  const tpl = "{{#loggedIn}}Hello{{userName}}{/loggedIn}}{{^loggedIn}}Please log in{{/loggedIn}}";
  Mustache.render( tpl, state );


Hmm, I see what you mean about pushing logic to the code calling Mustache, but I still wouldn't call it elegant with all the curly braces and explicit closing tags needed. JSX isn't elegant either in that regard which is why I work with React through ClojureScript.


Explicit closing tags are only needed when dealing with more complex examples, like basic conditional or loops (arrays). Rather than try to teach you on a hackernews forum, you can learn all you need to know about the syntax in 5 minutes here: https://mustache.github.io/mustache.5.html

There is even a ClojureScript implementation: https://github.com/fotoetienne/cljstache

Yes mustache, JSX and all the other templating syntax aren't pretty, but my point was that Mustache is the best I've come across so far. elegance and simplicity are in the eyes of the beholder though, so to each their own.


Elegant & simple?


Elegant & simple!


Wow. Do people consider this kind of coding acceptable now? We spent decades trying to separate templates, business logic, and inlined JS, and you managed to cram all three into a short snippet.


Yes and this is a tired argument by now. The talk by Pete Hunt aptly titled "React: Rethinking best practices"[0] given in 2013 points out how separating templates and logic is merely a separation of technologies, not concerns.

[0]: https://www.youtube.com/watch?v=x7cQ3mrcKaY


Thanks for posting this, it was really interesting. Everyone who criticizes JSX should have watched it before doing so.


Whether to show a logout link or a login form is presentation logic, not business logic.

I've spent decades telling people that trying to keep logic out of templates is a waste of time. A useful templating language has variables, conditionals, and even functions. There's no reason not to use a real programming language.

There's no good automated way to enforce MVC. How is an automated tool going to know whether "show this number to two decimal places" is a model thing (inherent precision of the data) or a view thing (presentation choice)?


>> Whether to show a logout link or a login form is presentation logic, not business logic.

I would prefer keeping presentation logic, or any logic for that matter, out of the HTML.


It's actually no different to any other templating solution. Take a look at this[1] Mustache.js example and note the logic! At least JSX is honest about what it is.

[1]: https://news.ycombinator.com/item?id=13153298


I guess honest can be a nice way of saying more verbose, just like elegant is another way of saying more terse and simple for those who get it


Agree. Looks like those who haven't suffered from it, can't live without this suffer. They just need to have this experience to be able to understand downsides.


4. This won't work if one of the branches errors, because they are both evaluated. You can, however, pass a callback. But a simple ternary operator does look better.


After making some simple <If> <Loop object="">, etc custom components.... I've wondered why they don't exist in react by default, or arent the common pattern.

They are very readable... maybe people just dont like the "logic" in a tag... i guess... whatever, made for some really readable code...


Regarding <If> component - here is the guy that suggested this and then admitted that this is a bad approach in a long run: http://stackoverflow.com/a/26152067/1132016


Using <If> combines the worst aspects of custom SGML template markup languages and the complexity of React but with additional runtime overhead.


Turns out javascript is a quite reasonable language and already does that great.


I would rather 'regular' JS functions like .map() rather than React-specific functions like <If> and <Loop> (not to mention the namespace clash with existing JS keywords)


For the first example, if you're willing to risk a stage-0 transform, you could try using a shiny do expression:

  render() {
    return <div>
      {do {
        if (loggedIn) { <a>Logout</a>; } 
        else { <form onSubmit={ ... } />; }
      }}
    </div>
  }


Not sure I understand your 3rd pattern, what does const {LoginForm} = this; do?


It is basically equivalent to `LoginForm = this.LoginForm`. It is called destructuring and is one of the nice conveniences of es6 javascript. Importantly you can also do this:

    var o = {p: 42, q: true};
    var {p, q} = o;

    console.log(p); // 42
    console.log(q); // true


It destructures this, to get the LoginForm property, it could be written <this.LoginForm> because even if it starts with a lower case character that are transformed as string when there is a dot it is transformed as object :

<component /> compiles to React.createElement('component') (html tag)

<Component /> compiles to React.createElement(Component)

<obj.component /> compiles to React.createElement(obj.component)




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

Search: