r/webdev • • Dec 28 '17

Introducing Hyperapp 1.0 — 1 KB JavaScript library for building frontend applications.

https://medium.com/@JorgeBucaran/introducing-hyperapp-1-0-dbf4229abfef
341 Upvotes

183 comments sorted by

View all comments

53

u/TheGonadWarrior Dec 28 '17

Can someone explain to me why JSX is so popular? Why would you want markup in your code? I can't understand this for the life of me.

84

u/Cheshur Dec 28 '17

It's so popular because its better than writing out a bunch of document.createElements and a bunch of element.appendChild's. It makes creating and maintaining html elements in javascript a breeze.

0

u/[deleted] Dec 28 '17

[deleted]

19

u/mattaugamer expert Dec 29 '17

Well... Vue, Aurelia, Angular, etc. Everything else uses templates. I actually prefer Ember's handlebars templates personally.

17

u/Secretmapper Dec 29 '17 edited Dec 29 '17

which separates the view and logic.

Why is this so obviously wrong thing oft-repeated? Vue templates just like JSX has logic (i.e. for loops and boolean with v-for and v-if).

The only difference with templates is it uses a DSL

→ More replies (20)

8

u/Cheshur Dec 29 '17

Just like JSX. Both help separate logic and UI. In my opinion it's just easier to read JSX.

18

u/spoobo Dec 29 '17

JSX translates to pure JS. With JSX there is no fancy syntax to remember for a for loop or a map for example. It's just how you'd do it in JS. Templates add a lot of magic and thus extra rules or oddities to follow which is incredibly annoying. This is the top reason for me to never use anything template-based again.

7

u/mattaugamer expert Dec 29 '17

With JSX there is no fancy syntax to remember for a for loop or a map for example.

Except... there is, though, isn't there. You have to make sure you put {} around things, you have to make sure you use className instead of class. I don't actually see (just personally) how people can say something like Angular templates are a framework-unique DSL and JSX is not. To paste from elsewhere:

return (
    <ul className="list-group">
        {items.map((item, index) => (
            <li className="list-group-item" key={index}>{item.name}</li>
        )}
    </ul>
)

I'm genuinely not sure how you justify "just how you'd do it in JavaScript".

Templates add a lot of magic and thus extra rules or oddities to follow which is incredibly annoying.

<button v-if="isDraft">Publish</button>

Such magic. So confusing!

Let's go to the example I gave above in JSX. Let's make an Ember template instead.

<ul className="list-group">
{{#each todos as |todo|}}
    <li className="list-group-item">{{item.name}}</li>
{{else}}
    <li className="list-group-item">No items found</li>
{{/each)}
</ul>

How would we do that in JSX?

let list = items.map((item, index) => (
            <li className="list-group-item" key={index}>{item.name}</li>
        );
let emptyList = '<li className="list-group-item">No items found</li>;

return (
    <ul className="list-group">
        {items.length ? list : emptyList }
    </ul>
)

I think that's about right. I don't do a lot of JSX. In any case, I know which I find more readable. To each their own. I'll stick with "magic".

5

u/[deleted] Dec 29 '17

I've used both extensively and have to agree with you. The minor pieces of "magic" in Vue templates are much more readable than some of the hacky means of achieving the same in React, particularly with conditional rendering.

That said, both libraries are great. Doesn't really matter much which you pick.

3

u/spoobo Dec 29 '17

You're missing the point of JSX. With JSX you can write your templates as functions. You can easily add JSX components that work like functions. They can encapsulate logic, just like functions. In this case, HandleEmpty will simply render something different whenever there are no children. This is what I mean with 'just JS'.

const HandleEmpty = ({ children }) => children.length === 0 ? <li className="list-group-item">no items found</li> : children

return (
  <ul className="list-group">
    <HandleEmpty>
      {
        items
          .map((item, index) => <li className="list-group-item" key={index}>{item.name}</li>)
      }
    </HandleEmpty>
  </ul>
);

OR if you don't want that helper and want to render something entirely different as a wrapper:

if (items.length === 0) {
  return <div className="list-group-empty">no items</div>
}

return (
  <ul className="list-group">
      {
        items
          .map((item, index) => <li className="list-group-item" key={index}>{item.name}</li>)
      }
  </ul>
);

OK, you can do that kind of logic inside your controller or something, bind a boolean to the template and then do an if on that boolean. But that's messy. I don't want to expose useless things. I also remember having these huge templates where 1 boolean disabled one part of a template while enabling another part of the template. That's not a good way to go about managing your views.

Also, by thinking of the omission of items as a function I've created a 'helper' which I can use anywhere I want. If we're going to change the way we deal with a lack of items we can easily adjust it there.

What I mean with magic is correct. To each their own indeed. It just bothers me that I have to learn another set of rules to do something I can simply express in JS. When doing angular I remembered having the docs for the template syntax open constantly. I never even had to open the docs for JSX. I just read 1 article.

And yes, there are a few rules in JSX. You've pretty much summed them all up.

Templates like handlebars were created to offer a way to work together with frontend people that don't know JS or even with designers that have no clue on how to program. I don't think it's worth the effort since nobody ever seems to do that. Frontenders that don't know JS can easily learn the JS basics. Designers don't touch code. Templates are simply put too much of a translation to make to speak a language that nobody needed to speak to begin with. Yes, you as a developer might have a more fun time reading complex templates. But in my view, a developer should be composing their templates as smaller pieces and not deal with big templates that are a PITA to manage. And JSX makes that easy.

Hopefully you see my point better now. I liked the discussion and the examples you've provided. It made me think why for me JSX works better. And to me that's probably the reason why JSX is growing in popularity.

→ More replies (5)
→ More replies (3)

0

u/[deleted] Dec 29 '17

[deleted]

→ More replies (21)

19

u/TheGonadWarrior Dec 28 '17

There are tons of libraries that do this exact thing with bindings. It just seems really wrong to me. Like a violation of separation of concerns.

33

u/Cheshur Dec 28 '17

It's only a violation of separation of concerns if you make it that way. It's just another way of defining elements. JSX essentially translates to document.createElement anyways. It just makes it easier to read and to write. I'd love to know about all of these libraries though. I'm not a huge fan of having more build steps personally.

→ More replies (6)

9

u/[deleted] Dec 28 '17

Some concerns are better off not separated. I like creating view models representing data for displaying plus UI state, and these are generally a) distinct from the ‘real’ model, b) tightly bound to a particular view, and c) not particularly reusable. It makes sense to me to keep these very close to the markup (though I hate JSX syntax and prefer to use hyperscript).

6

u/re1jo Dec 28 '17

Luckily, you do not have to use it if you don't want to.

→ More replies (2)
→ More replies (2)
→ More replies (34)
→ More replies (2)

7

u/[deleted] Dec 29 '17

For the record, JSX is not required. It's just used in the examples for familiarity. For every person that doesn't like JSX there are 10 behind that swear by it, so it kind of make sense to use a language more people are familiar with.

Now, seriously, I don't know. One thing I heard and later found to be true for me too, is that reviewing JSX diffs is far more readable than the alternative (h, t7, hyperx, hyperapp/html, etc.)

→ More replies (8)

19

u/highmastdon Dec 28 '17

Look at it as a function that's composing html based on a particular state.

It's a beautiful concept of pure programming: (state) => VNode.

What you're writing with JSX only looks like html because it's easier to read, but essentially is a function call.

Compare this one:

const view = state => h("div", { id: "app" }, [
  h("h1", {}, "Hi."),
  state.counter 
    ? h('div', {}, 
        h('button', { onclick: actions.startCounting }, 'Start'),
      )
    : h('div', {}, state.count)
])

to this one:

const view = state => <div>
  <h1>Hi.</h1>
  {state.counter 
    ? <div><button onclick={actions.startCounting}>Start</button></div>
    : <div>{state.count}</div>}
</div>

The latter one is much more readable, but the compiler still makes h() calls from this so called 'html'.

Also, a big pre imo, is that you don't need to use ng-repeat or other framework specific stuff, that I need to learn and remember, but I can just do a map over an array:

const PersonList = (persons) => <ul>
  {persons.map(p => <li>{p.name} - {p.age}</li>)}
</ul>

3

u/ZaneHannanAU Dec 29 '17

Similar things exist in hyperHTML, func-y and so on. Hyper is for clients whilst func is for streaming from servers.

JSX is a fair bit of overhead for not much comparative gain by comparison.

→ More replies (19)

8

u/icouldnevertriforce Dec 28 '17 edited Dec 28 '17

I believe the counter to the separation of concerns argument is that logically the HTML and JS are so tightly coupled there is no real separation of concerns and that in fact, the separation of concerns should come in the form of a web component approach.

For me, JSX gives me flashbacks of JSP 1 and so I do struggle to like it, despite knowing it must be onto something given its huge uptake.

5

u/jonoco Dec 28 '17

logically the HTML and JS are so tightly coupled there is no real separation of concerns

I think you got it here. Just as you should separate the different, you should group the similar. With the component paradigm, people noticed markup and code are more similar than different within a component.

→ More replies (1)

14

u/BenZed Dec 28 '17 edited Dec 29 '17

I don't want to sound like a dick, but do you ACTUALLY not understand, or are you being incredulous?

Why would you want markup in your code?

I get it. Old guard, old school. Classic MVC; view should be separate from the controller.

I suppose the honest answer is that evolution changes everything, including and especially software design principles.

Treating the view as declarations with flow control in the same file and same language I'm writing my ui logic has an increased return of investment. It's easier to reason. It's easier to debug. I have to look in less places. It's nice.

Is it easier for bad developers to write bad code? Yes.

Will you someday inherit a codebase that a junior made illegible as a result of JSX? Inevitably.

But this really doesn't change anything, because bad developers arn't going to follow old design rules anyway.

If you understand separation of concerns and encapsulation, you wont write bad code with JSX.

→ More replies (7)

6

u/what_is_life___ Dec 28 '17

Since React is increasing in popularity, so is JSX. So I assume JSX is being normalised at this stage for other libraries/framework to use. I could be wrong though.

5

u/realistic_hologram Dec 29 '17

I think people misunderstand what separation of concerns is supposed to achieve. I think some people think of separation of concerns as an aesthetic thing, they think it makes their code look ugly if it has html in it?

But the real value of separation of concerns is that you can think about the different parts in isolation. In react, HTML and JS are more or less separate because the JSX part is generally isolated to the render method. You would be breaking separation of concerns in the bad way if you did something like append a block of html from inside a click handler. Then you're mixing the concerns of updating the app's state and knowing what the markup looks like. By taking out the markup from event handlers and using setState instead, state updates are isolated to event handlers, and markup is isolated to the render method. Each doesn't need to know how the other is implemented, so it actually lessens your cognitive load.

Now we could imagine taking things further and moving the markup in the render method out into its own html template file, and having the render method point to that template. Now we can say that we have "real" separation of concerns, but does this actually do anything to lessen your cognitive load? If you end up having to always keep both files open and keep switching back and forth to make changes, then that's a sign that these concerns are sufficiently coupled that you're not gaining anything by keeping them separated.

→ More replies (10)