DEV Community

Why React? Because it's pretty cool actually. Misunderstood at times, but cool ๐Ÿ‘

Brad Westfall on August 04, 2021

A hopefully well received and educational response to "why react sucks" - https://dev.to/jfbrennan/really-why-react-5958 JSX templates JSX is n...
Collapse
 
daweet profile image
Numbnut • Edited

React.createElement is the underlying API for React to which JSX was created specifically to compile to.

ึผ

JSX is designed to be nested function calls that look familiar to us like XML or HTML so our eyes don't burn when look at actual nested function calls

ึผ

Some who don't know might complain that in JSX we do instead of HTML's . But again this is how it's done in plain JavaScript. Checkout the MDN docs for yourself ๐Ÿ˜‰

You are stating the obvious, and presenting it as if you are "correcting" the OP - but the OP knows this and his original point is still valid: JSX is made to look like html, but is actually not. The JSX design decisions are somewhat understandable, but the OP was criticizing the reliance on JSX, not JSX's design decisions, while you're justifying their design decisions. In my opinion, there is no justification for using JSX as a library requirement, when tagged template literals exist.

JSX looks like html but it introduces variations from the standard (className instead of class, style attribute, etc.). And those are really irritating for someone who doesn't want to forget the web standards and commit fully to react. So react is like a jealous partner in that aspect, it tries to push you away from the obvious alternative and make you choose between the two. Only react is a "library", right? It shouldn't try to push you away from web standards.

Collapse
 
bradwestfall profile image
Brad Westfall • Edited

"there is no justification for using JSX", "react is like a jealous partner". Stop being dramatic. We'll have to agree to disagree. All abstractions of HTML creation deviate from HTML in certain ways. You're complaining that JSX deviated away from standards when the whole point of JSX is to make the DOM and it is using standard DOM API names like htmlFor vs for. Isn't it weird that the "I hate JSX" crowd is so loud about the certain ways that JSX is different from HTML and yet they're using string-based abstractions that do things like <button onclick=${() => state.clicks += 1}> and for whatever reason their control flow decisions which don't resemble HTML are forgivable and are supposed to be easier for newcomers to get over JSX? Show me in the w3c where your library's syntax meets the HTML standard for onclick=${() => {}}

Collapse
 
daweet profile image
Numbnut

You're right, no point in being dramatic. But you get what I mean when I say that "react is like a jealous partner", right? It makes you learn lots of stuff, while unlearning the standards. And that's how you get a divided community, because unlearning react takes time so managers tend to stick with it and people tend to find justifications for keeping using it. "I know it so I should use it" is really an ok justification, people just gotta be aware of their own reasons.

Isn't it weird that the "I hate JSX" crowd is so loud about the certain ways that JSX is different from HTML and yet they're using string-based abstractions that do things like

The difference between JSX and what "I hate JSX" crowd strives to, is that the only deviations are in added functionality - basically, how values are inserted, instead of a whole lot of other deviations in existing functionality. Let's look at onclick.
onclick=${() => {...}} is a deviation from the standard indeed, but there's no way to do this in html, and in my opinion it's the simplest way to respond to events in a clear, inline manner. React does this similarly.
But className, style attribute, camelCase attributes, the extra compilation step, all that doesn't cut it with me, especially when it's combined with a framework that requires it to be usable, with the framework itself having a few questionable design decisions.

Thread Thread
 
bradwestfall profile image
Brad Westfall • Edited

I appreciate it, but you're splitting hairs talking about how your way of "expanding what is possible" with HTML by adding functionality is hugely different from what JSX is doing. Also, what you're saying about devs using React is somehow bad because they won't learn standards -- that has nothing really to do with React. When jQuery came out everyone said the same thing, and they were right. People were learning jQuery and not understanding how the underlying DOM works and when they jumped over to Angular they had to learn new stuff -- and that's okay. Then Angular got popular and bootcamps became a thing and the bootcamps were only teaching Angular without really teaching good fundamentals (the standard). Let's not act like React or your tool if it were to become popular are any different. Devs are devs, people are people, if they have a tool available to them that helps gloss over the ugliness of the DOM they're going to use it

Thread Thread
 
daweet profile image
Numbnut • Edited

Glossing over is fine, and abstractions will always put an extra learning layer and require the dev to know his fundamentals.
Agreed. But inventing new ways to do the same stuff with the same ugliness rating of the underlying tech, that's what I dislike... And that's what JSX has - unnecessary deviations from standards. You can't call className an abstraction... It doesn't abstract anything, It's just a simple patch for a design flaw.

If my tool becomes popular maybe people will complain about it, but it won't be for creating unnecessary deviations from standard html. (Really, check it out, it's pure html plus expressions for reactive values...).
It is hugely different from JSX - it doesn't require a compilations step, it's just legit JS code. There's no new html-like syntax to learn. The actual rerender mechanism is embedded into the template unlike react (it's a render - once template). No VDOM. The diff is huge, really :)

By the way, what did you mean by "control flow decisions which don't resemble HTML"? Html doesn't have control flow decisions. Did you compare the {condition && someConditionalContent} syntax that Yoffee and react use with Vue's v-if tags?

Thread Thread
 
bradwestfall profile image
Brad Westfall

Yea, I'm saying if it aint exactly HTML then I guess we can say it deviates from the "standard" if that's the strict set of rules we're upholding things to. I'm not the one saying that but the JSX hater crowd seems uphold this for JSX and conveniently ignore that they (angular, vue, yours probably) do control flow in various ways that also isn't exactly HTML so to me that's splitting hairs (bike-shedding) over syntax which really doesn't matter

Thread Thread
 
bradwestfall profile image
Brad Westfall

Like, one of the main points that other article made was something to the effect of: "I can't copy JSX into another project as HTML and that rubs me the wrong way...", what, like you can with any of these template lang DLS syntax? The JSX hater crowd is one of the more ridiculous that Ive seen with their arguments and I've been doing this shit for 22 years

Thread Thread
 
daweet profile image
Numbnut

Well, the author should have specified that he needs to do much more work copying JSX to another framework than copying code of libraries that use tagged template literals. The author may have accidentally implied that it's actually possible to copy from framework to framework, but to me it didn't seem so and his point was fairly clear.

The hater crowd, me included, sees that some things should be much easier than they are, even if the popular way is not so terrible.

Thread Thread
 
bradwestfall profile image
Brad Westfall

No worries. I'm sure we each have better things to do today, we can agree to disagree on JSX ๐Ÿ˜Š

Collapse
 
peerreynders profile image
peerreynders • Edited

that will never be able to do as many things as it's host language.

And that is exactly the point of a templating language - to constrain capabilities to what is essential to rendering the representation while not facilitating the execution of business/domain logic.

From that perspective JSX is just as problematic as Ramus Lerdorf's PHP back in 1994:

โ€ฆ and I tried to convince people that you should write the business logic in C and use my templating system, โ€ฆ Nobody agreed with me. Everybody just wanted to write their business logic in the templating system and it was very discouraging to me for years โ€ฆ Eventually I had to sort of give in and say, OK, fine, yes, โ€ฆ

Almost twenty years later JSX committed the same error that Rasmus Lerdorf was pushed into by his user community. Back before 2013 when React was conceived CSR was the new hotness and the web was still largely being consumed on large core desktop computers through hard-wired, rock-solid network connections, so pre-rendering wasn't even given a second of thought.

But these days it's SSR this and SSR that which ultimately leads to the franken-setups that are necessary to pre-render client side frameworks on the server side. So a contemporary solution would be a templating language where the same template fragment can be used equally on both on the client and server side independent of the host language. On the server side the template would be compiled to a host function that essentially just concatenates strings to produce the necessary markup while on the client side the template would compile to a function orchestrating the necessary DOM or framework calls.

And as I noted elsewhere:

The issue is that most JSX code conflates code to control templating with code to enable interaction behaviour.

From that perspective it makes sense to organize JSX "as if it were a template" to get a clear separation between the interaction logic and the representation. Example:

import { h } from 'preact';
import { useContext, useState, useEffect } from 'preact/hooks';
import { Shop } from './shop.js';
import { Loading } from './loading.jsx';

function renderBook(book, addToCart) {
  return  (
    <section class="page-book">
      <h2>{ book.name }</h2>
      <p><i>By: { book.author }</i></p>
      <p>Price: { book.price }โ‚ฌ</p>
      <button onClick={ addToCart } >Add to cart</button>
    </section>
  );
}

function makeSubscription(books, [last, setCurrent], id) {
  const listener = (current) => setCurrent(current);
  return books.subscribeBook(listener, last, id);
}

function BookDetails({ bookId }) {
  const { books, cart } = useContext(Shop);
  const pair = useState(() => books.currentBook(bookId));
  useEffect(() => makeSubscription(books, pair, bookId), []);

  const [ book ] = pair;

  if (!book) return <Loading />;

  const addToCart = (_e) => cart.addBook(bookId);
  return renderBook(book, addToCart);
}

export {
  BookDetails
};
Enter fullscreen mode Exit fullscreen mode

And from the server perspective JSX being "just JavaScript" is a problem because it means having to support JavaScript on the server even when the rest of the back end is pre-dominantly implemented in a completely different host language.

Aside: The Case Against Logic-less Templates


the main idea is that any programmatic way of building DOM nodes is messy when it comes to nesting.

React.DOM used to supply DOM factory functions which were later moved into react-dom-factories (only work pre-16.0.0).

import { div, h1, p } from 'react-dom-factories';

div( null,
  h1( null, 'Hi, welcome to React DOM factories' ),
  p( null, `It's just function calls` )
);
Enter fullscreen mode Exit fullscreen mode

That is no-more-awful than hiccup which ClojureScript programmers routinely use to describe markup - and it's actually just function calls - no preprocessing/transpilation required.


You can't do statements in JSX because you can't do them as arguments to functions

More to the point expressions and functions return a value (even if it is undefined) and that value can serve as an argument for createElement.


JSX is designed to be nested function calls that look familiar to us like XML or HTML

Right - and that familiarity is a hell of a drug - and that's why JSX is popular and despite how much people assert "it's just JavaScript" and "it's just an XML-like syntax extension" subconsciously they are still perceiving and thinking HTML, so running into className and htmlFor, etc. creates cognitive dissonance - which is why Preact got rid of those inconsistencies. The other alternative would have been to abandon an HTML look-a-like altogether.


This is why you also can't do this and return two JSX nodes -- because they're function calls:

โ€ฆ and that is what fragments are for:

ReactDOM.render(
  <>
    <div></div>
    <div></div>
  </>,
  document.getElementById('root')
);
Enter fullscreen mode Exit fullscreen mode
'use strict';

ReactDOM.render(
  /*#__PURE__*/ React.createElement(
    React.Fragment,
    null,
    /*#__PURE__*/ React.createElement('div', null),
    /*#__PURE__*/ React.createElement('div', null)
  ),
  document.getElementById('root')
);
Enter fullscreen mode Exit fullscreen mode

โ€ฆ and this lines up with the notion of a DocumentFragment which is necessary as there can only be one single document root per document tree.


Again, it's not meant to be HTML

  • That is correct on a technical level.
  • But on a psychological level that statement is sooo wrong - the acceptance of JSX hinges on the fact that it looks and feels like HTML which makes it even more irritating when it deviates from actual HTML. Saying "it's just function calls" doesn't fix that. Then make it actual function calls and don't just "put lipstick on a pig" by making it almost look like HTML.

A lot of people who are critics of JSX will say "why does it have to be different from HTML...?"

In Preact the attribute names aren't different from HTML. But of course by now there is a huge React-dependent code base out there that has already committed to the DOM-specific rather than HTML-specific attribute names.


And again, since this is a function callโ„ข, we can do that.

And again, if that is the issue then stop making it look like HTML and just make it a function callโ„ข.


so they created hooks to give us a primitive API for sharing code.

I'm not even sure that hooks are the correct means for sharing code (sure, they're being used that way) from a software engineering perspective. I'm leaning towards sharing code via context - provided context is used correctly:

context is ready to be used for low frequency unlikely updates (like locale/theme). It's also good to use it in the same way as old context was used. I.e. for static values and then propagate updates through subscriptions. It's not ready to be used as a replacement for all Flux-like state propagation.

Hooks themselves seem to be an API for the component to access component instance specific state as it is managed by React itself. As such complecting actual application specific code into hooks seems to be the road to a Big Ball of Mud as the application grows. The "React is your application" development style seems risky for larger applications (UI as an Afterthought).


There are only two ways to make components

Historically there are many more:

The internet is full of tutorials all the way back to 2014 and even React's own documentation still features many React.Component examples - it's not clear when everything will have been updated to the "hooks" standard.

-- functions and classes

And for someone just familiar with vanilla JavaScript that in itself can be tremendously confusing.

Typically the association between Component <-> class is easy enough to make but the first hurdle is understanding is that the object created by the custom class isn't actually in charge of the custom component instance's state - but React is via setState().

The vast majority of the React community is embracing functions because of hooks.

And I have no idea how newcomers are expected to understand the role of hooks (much less how they work) without understanding class components first.

Pure function components are easy enough: props in -> ReactNodes out - i.e. exactly the way one expects a function to work. But impure function components with hooks?

Coming from class components one at least has a chance to understand that a function component is essentially just a render() function. The leap is to then realize that hooks are the access point to the component instance's "guts" - at which point the function component becomes the central orchestrator of the component instance passed to it via hooks (I still think that Inferno's approach of passing lifecycle handlers as separate functions may be more intuitive than using useEffect()).


So it's not like we're sitting around going "Should I use a mixin today or an HoC or a hook".

As Mark Erikson points out using hooks rather than HOCs can have undesirable consequences under certain circumstances - so "it depends".


In React, the reason why two React developers might have a disagreement is because one might want to use Redux and one might want to use context.

Actually the divide is how much state React should actually be responsible for:

  • React is your application (component-centric) vs.
  • React is not your application (app-centric)

Obviously React has to be responsible for component state otherwise it wouldn't know when to re-render - but when it comes to (client side) application state the larger the application is the more hands off React should be.

Also React really ought to be stating "A JavaScript libraryโ„ข for building user interfaces" - I recently had a lengthy discussion about that. The simple truth is that React pushes you to develop apps in a certain way in order "to be productive" - but the path of least resistance isn't necessarily the best path for long term maintainability (I guess it doesn't matter if everything gets re-written every two years).


the "disagreements" mean that there's discussion and the best ideas rise to the top.

I disagree. It has been my observation that what is popular (easy and familiar, rather than simple) rises to the top. At the same time popularity has little correlation to quality.

Collapse
 
bradwestfall profile image
Brad Westfall

They were misleading and inaccurate. That's the bottom line.

Collapse
 
kputra profile image
K Putra

But the points are about over engineered, performance, spaghetti code, etc. While I agree with you that some of the informations are perhaps misleading, but there are many bitter truths.

When I first wanted to learn front end, I have to chose which one should I learn. When I compared Angular, Vue, and React (three among the most popular), I saw React is pretty complex and the performance is not good comparing to others. And as the previous article stated, "If you have to make a solution for a solution, then the first solution is not a good solution." And thats what I saw in React. Well, this is something you have to overcome if you want backward compatibility. Over engineered? So much. Add typescript, and you get a spaghetti monster code.

But then I still learn React instead of others. Because it's the most popular and the easiest to land a job as a full stack in my country.