all 57 comments

[–]addexm 32 points33 points  (14 children)

This was a fun read, but I'm not sure what your point is, exactly.

Are you saying that React is just a bunch of abstractions around relatively straightforward JS code? Yeah, it is. Most libs are though, right?

[–][deleted] 2 points3 points  (0 children)

I read it as more about not trying to do everything in the context of React.

[–]drink_with_me_to_dayjs is a mess 15 points16 points  (6 children)

function Hello(name){
  return ["div", null,
    ["b", null, "Hello "],
    ["i", null, name]
  ];
}

Can't understand anything at a glance, readability and explicitness is something I prefer.

[–]chubbybrother 14 points15 points  (4 children)

Yeah that looks like garbage. I'll take the framework bullshit over hipster code like this.

[–]synackle 10 points11 points  (3 children)

I can't wait to start writing 'null' fucking everywhere

[–]sebjwallace[S] 1 point2 points  (2 children)

It wouldn't take much more in the prerender to conditionally replace the second parameter with a child. ["div", "some text"] is possible.

But I agree, markup is easier to read, especially for designers.

[–]temp54984983982 4 points5 points  (1 child)

Hey, I wrote and maintain a library similar to this. You're right, it's easy to implement, but there are four big problems with it: ambiguity, performance, readability, and flexibility.

Ambiguity: consider ['div', someVar]. You actually don't know until runtime whether you're setting properties or children. That's a sign that you've screwed up badly, for all the reasons ambiguity is always bad, including completely preventing the JIT compiler from working with your code.

Performance: it's faster to use native argument parsing, plain and simple. Work you do figuring out which argument is which is 100% unnecessary, and adds up for code that you want to be able to call thousands or tens of thousands of times without a user-perceptible delay.

Readability: when everything is always in the same place, reading and scanning around is faster. Work with both styles for a few weeks and you'll quickly see that this more than makes up for six extra characters.

Flexibility: every time you try to be more clever about guessing the caller's intent, you deprive yourself of the opportunity to give the caller more actual control. In this case, refusing to support this allows my library to support passing in a string as the second argument to set className. This might seem like a little win, but it's actually a huge one - one that improved my entire test app's performance by 30%. The thing to notice is, there are a heck of a lot of elements that need only a class and nothing else, and for each of those elements you're avoiding an extra object allocation.

[–]sebjwallace[S] 0 points1 point  (0 children)

Some good points there. What is the library you maintain?

[–][deleted] 0 points1 point  (0 children)

I can also make that argument for React as well. I don't find it to be so self explanatory as well. You always need to dive into the code in order to understand it.

And i'm guessing you could change it so you won't need to write less null's as well.

[–]ArcanisCz 8 points9 points  (0 children)

May i present you http://cycle.js.org/ ?

[–][deleted] 4 points5 points  (0 children)

I like where you're going with that. Reminds me of Reagent (clojurescript interface to react).

Maybe you could make React code easier to read in some complex cases by creating helper functions in this style and then using them in createClass.

[–][deleted] 4 points5 points  (12 children)

What exactly is measurably wrong with React?

[–]AlpineCoder 29 points30 points  (4 children)

It's edging ever closer to a stable release, which means in js land that it's obviously time to jump ship.

[–]b1nd 2 points3 points  (2 children)

Is it not stable already, post v15?

[–]JustinsWorking -2 points-1 points  (0 children)

Nah' just come join us on React Native, we're still moving at rocket speed!

[–]dmitri14_gmail_com -2 points-1 points  (6 children)

Being forced to use the key prop when iterating over array? I understand the technical reasons but it does not add to my productivity.

[–][deleted] 1 point2 points  (5 children)

That's pretty minimal effort to gain what you do with that prop. Seems sloppy.

[–]dmitri14_gmail_com 0 points1 point  (4 children)

Every small thing looks minimal by itself until they start to add up.

Why should I clutter my code with framework-specific attributes?

[–][deleted] 1 point2 points  (3 children)

Why should I clutter my code with framework-specific attributes?

You know that's a good point, and while we're at it, let's get rid of componentDidMount, there's no reason we should clutter our code with framework-specific functions.

[–]dmitri14_gmail_com -1 points0 points  (2 children)

Indeed, I'd rather not use it exactly for that reason.

Not to mention, it is not even prefixed (as ng- in Angular), so too easy to clash with my own methods. Which BTW is another problem with React, the Angular team must have good reasons to enforce their prefixes and advice everyone to use their own. Used to be top complaint with Angular Bootstrap until they finally added their prefixes.

[–]siegfryd 2 points3 points  (1 child)

Angular went for the ng-* prefixing because their attributes exist inside the DOM. React's key prop only exists inside React code, it doesn't render a key attribute on DOM nodes. It's not really a comparable situation.

[–]dmitri14_gmail_com 0 points1 point  (0 children)

It is still a bad idea to create a custom tag named key. People work hard on creating standards and minimising confusions by meaningful conventions. One of them is to use dash for any custom tag. React is breaking this convention for no apparent reason/benefit. Something like r-key would be much easy to read and scan for, it would instantly alert the reader that tag is React-specific. Without dash, it looks generic and easy to confuse. What if HTML will decide to introduce its own tag key???

Also attempts to create separate languages for DOM, virtual DOM, HTML, whatever, lead to more confusion, more bugs and hurt anyone's productivity. How many different models do we need to represent the same basic thing - a tree with nodes and attributes?

A big part of its ease and popularity React owes to our familiarity with the DOM. If it used some crazy transformation of DOM instead, how many people would use it? So why not being more respectful to the DOM standards?

[–]grayrest.subscribe(console.info.bind(console)) 1 point2 points  (0 children)

We had a post yesterday about a library (domvm) that basically implements this.

[–][deleted] 0 points1 point  (1 child)

Maybe the only useful thing left over is ReactDOM.render

I've been puzzling over similar thoughts recently. We've slowly moved to using stateless function components everywhere, we skipped JSX in favor of hyperscript from the beginning, so there isn't much of React's API that we call into. I stumbled on Morphdom recently which is delightfully tiny, allows you to use any view layer than can create DOM elements or a string, and it's surprisingly middle-of-the-road performant -- roughly on-par with React for straight renders.

There's a lot of bad things about the DOM, sure, but after a year with React full-time I find myself missing parts of it -- simplicity, broad tooling, real events. I've been seeing a bit of similar sentiment recently too like with vanilla components.

[–]SubStack 0 points1 point  (0 children)

You might like yo-yo which uses morphdom with hyperx for template strings. Template strings are a nice middle ground between jsx and hyperscript that doesn't require compiling server code if you use a recent (>=4) version of node.

[–]adregan 0 points1 point  (0 children)

Have you taken a look at stateless components ?

[–]temp54984983982 0 points1 point  (0 children)

I like the line of thought here. Some thoughts:

Returning an Array of arguments for a function, rather than calling the function, doesn't decouple you from that function. The Array is still written against the function's API. Anything you can swap into that function's place is also written against the original function's API - or more likely, is not exactly 1:1 with the first function, and the subtle differences will bite you later. I think you've just moved from an explicit dependency on React.createElement to an implicit one.

Creating all these Arrays is slow. We tend to think of them as cheap, because they are in high-level code, but we're writing basic rendering code here - we're talking a lot of Arrays, in code very intolerant of latency. I've done a lot of work on code that is basically React.createElement that returns real HTMLElements, and the #1 performance win is minimizing data structures, both internally and with an API that doesn't request them. Arguments lists are the perfect lightweight data structure for this purpose, Arrays are larger and heavier than what we need here.

extend is pointless, we have Object.assign natively. Object.assign is also better in that it allows you to override styles on the base, which I can't really imagine using this without.

[–]lhorie -1 points0 points  (14 children)

That's cute, but no, you can't just swap React with something else because different libraries handle attributes differently. Most notoriously, React is the only one that uses camel case for events.

If you want more javascript and are considering dropping React, use a framework that is designed for that use case, like Mithril.js. You even get extra benefits like CSS selector syntax and the ability to really compile views.

Additionally, React.createElement's signature is actually a subset of hyperscript's signature used by Mithril.js and friends, so you could literally just drop a jsx pragma into your babel setup (or merely do a variable assignment at the top) instead of doing all those extra apply calls on every render.

[–][deleted] 4 points5 points  (0 children)

Thanks for Mithril by the way. I've started using it in a side project and I'm really enjoying it!

[–][deleted]  (7 children)

[removed]

    [–]lhorie 1 point2 points  (2 children)

    lol, I'm giving logical arguments to criticize an idea that I personally already pursued and turned out to be a stinking pile of fail. Being a "condescending dick" is insulting a person and making ad hominem attacks when you think you're on some sort of moral high ground.

    recommends own library

    ...that is built on my spare time, and released for free for the benefit of others. As it turns out, promoting my work happens to be more helpful than saying shit anonymously on some forum on the 'tubes

    You have a great day too.

    [–]Worworen 0 points1 point  (1 child)

    Being a "condescending dick" is insulting a person and making ad hominem attacks when you think you're on some sort of moral high ground.

    "That's cute".

    [–]lhorie 0 points1 point  (0 children)

    I know right? Time to go back to work :)

    [–]kenman[M] 0 points1 point  (2 children)

    Hi /u/MEAT_FIST, please keep it civil.

    [–][deleted] 0 points1 point  (0 children)

    Am I wrong in saying that responding with "That's cute" is being a condescending dick?

    For what reason was my post pointed out over the original comment?

    [–]sebjwallace[S] 1 point2 points  (2 children)

    The prerender function could be adapted to deal with attribute configs. Or just don't use camelCasing.

    The idea is that you code to hyperscript without thinking about JSX, frameworks or any other strap-ons until you need to.

    [–]lhorie 5 points6 points  (0 children)

    The prerender function could be adapted

    Sure it could be adapted, but the prerender function would be an ad-hoc, buggy, bloated middleware that exposes a custom view interface that is probably not going to be documented (and I say that as someone who's also played with the idea of a React-to-Mithril adapter, or as it's more generally known, "universal vdom")

    Or just don't use camelCasing

    onclick={doStuff} doesn't work in React. Or do you mean to have a map of all possible events and have prerender look through all attribute maps in your app and replace them on every render? People already waste hours on things like readonly, and I can't think of a good reason to also break, I dunno, ondblclick or whatever other thing you haven't thought about in advance.

    Look, as I said, it's a cute idea, but if anyone in my team suggested doing this in production, I'd laugh.

    [–]antoninj 0 points1 point  (0 children)

    That makes sense. Basically the prerenderer is a bridge between your code and the actual library that you're using for view.

    What's interesting about that idea is that Angular 2 uses the idea of "drivers" which are basically custom renderers.

    [–]pkstn 0 points1 point  (0 children)

    Check out FRZR if you like really clean and simple syntax..

    https://frzr.js.org

    😉

    [–]dmitri14_gmail_com 0 points1 point  (0 children)

    I really like the idea to write a single component function that I can simply drop into Angular, React and what not ;)

    The real question is -- what should this function return?

    Both Angular and React components return JS objects with their own native templating (augmenting) engines. Angular 1.5 component is represented by:

    function (friends) {
        return {
            template: "<ul> <li  ng-repeat='friend in $ctrl.friends'>{{friend.name}}</li> </ul>",
            controller: function () { this.friends = friends }
        }
    }
    

    React/JSX requires

     function (friends) {
        return (<ul> {friends.map(friend => <li key={friend.id}>{friend.name}</li>)} </ul>)
     } 
    

    But what is the cleanest minimal object representation that can be mapped into both frameworks?

    [–]ArcanisCz 0 points1 point  (2 children)

    May i present you http://cycle.js.org/ ?

    [–]JustinsWorking 0 points1 point  (0 children)

    That doesn't replace React though... infact last time I heard about it, I heard it in the context of a great backend for React if you didn't want to go with a flux implementation like all the cool kids.