DEV Community

Brad Westfall
Brad Westfall

Posted on

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

A hopefully well received and educational response to "why react sucks" - https://dev.to/jfbrennan/really-why-react-5958

JSX templates

JSX is not a "templating language", it's actually considered to be the antithesis of one. Templating languages suffer from becoming a DSL (domain specific language) whereby the "language" must recreate things like conditional logic and iterations with some proprietary "template language syntax" that will never be able to do as many things as it's host language.

JSX was added as a way to avoid using React's own createElement API.

Not at all, React.createElement is the underlying API for React to which JSX was created specifically to compile to. It's not like JSX was created long after React to "avoid something". Instead, the main idea is that any programmatic way of building DOM nodes is messy when it comes to nesting. For example it's horrific in jQuery or vanilla JS. So instead of nesting function calls like this to make DOM nodes:

React.createElement(
  "div",
  null,
  React.createElement("h1", null, "Hi, welcome to JSX"),
  React.createElement(
    "p",
    null,
    "It's a function call, not a tempesting language"
  )
);
Enter fullscreen mode Exit fullscreen mode

πŸŽ‰ You can write this which is also nested function calls:

<div>
  <h1>Hi, welcome to JSX</h1>
  <p>It's a function call, not a tempesting language</p>
</div>
Enter fullscreen mode Exit fullscreen mode

To use JSX is to call a function:

const message = 'I teach workshops at reacttraining.com'
<div>{message && message.substr(0, 7)}</div>

// compiles to
React.createElement(div, null, message && message.substr(0, 7))
Enter fullscreen mode Exit fullscreen mode

And because it is essentially a function call we can think of props as arguments. We can avoid doing DSL nonsense and have the full power of the host language (JavaScript) by way of JS expressions.

So why only expressions? πŸ€”

Because again, it's a function call. You can't do statements in JSX because you can't do them as arguments to functions:

// Nope, not allowed
<div>{if (condition) {}}</div>

// Because it would compile to this:
React.createElement(div, null, if (condition) {})
Enter fullscreen mode Exit fullscreen mode

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 but also with the easy and power of a full programming language.

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

function App() {
  return <div></div><div></div>
}

// Compiles to 
function App() {
  return React.createElement('div') React.createElement('div')
}
Enter fullscreen mode Exit fullscreen mode

And you can't just call two functions back to back

If you ever see {' '} in JSX, that's because in HTML (which JSX is not) white space is treated a certain way. More than one whitespace character is reduced down to a single whitespace. Because JSX is a function call, it kinda sucks I'll admit, but you have to do {' '} in a few scenarios to create whitespace. On a really big project I might have to do that like 4 times, not a big deal.

Because of all this specialness you can't easily port JSX. That rubs me the wrong way. Template code should be easy to port because HTML is a standard.

Again, it's not meant to be HTML

For example, in JSX you do:

<div className=""></div>
<label htmlFor="" />
Enter fullscreen mode Exit fullscreen mode

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

Did you know "The class is an HTML Attribute, while the className is a DOM Property." - MDN

Turns out there's always been a difference between HTML and JS in terms of what an HTML attribute is and the corresponding way to modify that thing in JS. The same is true for <label>. Some who don't know might complain that in JSX we do <label htmlFor=""> instead of HTML's <label for="">. But again this is how it's done in plain JavaScript. Checkout the MDN docs for yourself πŸ˜‰

For example, the perfectly valid <label for=""> will not work because for gets parsed as JavaScript. You have to use a funny JSX attribute: <label htmlFor="">.

I think we covered that one.

Also, you have to do a funny comment syntax because HTML comment syntax is not allowed.

It's not HTML πŸ‘†πŸ» The reason for the "different" not "funny" comments is because Babel would confuse these comments for being content -- like if you were documenting how HTML comments work:

<div>
  <!-- HTML comment -->
</div>
Enter fullscreen mode Exit fullscreen mode

And don't forget to slash your self-closing tags, e.g. <img />, even though HTML5 dropped that syntax more than 10 years ago.

Actually not really true. XHTML was going to be a thing in the 2000's so browsers started to implement some of it. The W3C eventually ditched the idea and did HTML5 but not before things like trailing forward slashes were already implemented by most browsers. Today, we can still do "XHTML" style self-closing tags on <img /> <-- that's valid HTML, it's not "dropped" it's just left over baggage from an old W3C idea that the browsers kept.

By the way, JSX stands for "JavaScript and XML" -- because it's a JavaScript function call (have I said that already) with XML (not HTML) syntax. In XML you do have to close your self closing tags with a forward slash.

Another one I still don't understand and don't want to understand is: Error: The style prop expects a mapping from style properties to values, not a string.

It's easier to programmatically make inline styles if we express them as an object. And again, since this is a function callβ„’, we can do that. This feature has also played a big role in developing things like CSS-in-JS which you can decide you don't like or you just don't like that it's an object. But it's not a "ridiculous speed bump".

[React is an] "unmanageable mess" [because of] Functional or Class-based, controlled or uncontrolled, forwardRef, mixins, HOC, Hooks, etc.

That's not the point they were making. Because React lost a primitive (mixins) for sharing re-usable business logic when they switched from their original API to classes, the community (not the React library) came up with some patterns to share code, one of those patterns was HoC which has a way of double or triple wrapping your components in other components in order to solve the problem of sharing re-usable code. This meant that when you "look at a typical React application in React DevTools" there's extra wrappers in the component viewer (not the actual DOM). The React team realized for many reasons that not having a primitive way to share code was causing React developers to do things that were a little more messy, so they created hooks to give us a primitive API for sharing code.

In no way were they trying to say that React is messy because of that list. This whole section was kind of reaching for things that aren't really there to fit into a narrative.

The fact that there are so many options and types of components confuses me.

Clearly πŸ˜•

There are only two ways to make components -- functions and classes. The vast majority of the React community is embracing functions because of hooks. There are three ways to make functions though in JavaScript so maybe that was confusing? But that's not React's fault.

Those other things (controlled or uncontrolled, forwardRef, mixins, HOC, Hooks) are not components, they are "features" to which components can have and some of them are alternatives to each other so it's not like all of those are used at the same time. Some are even from different time periods (mixins the first API, Hoc's the abstraction for classes we dont' use because hooks exist now. etc). So it's not like we're sitting around going "Should I use a mixin today or an HoC or a hook".

When a tool can be used in so many ways it creates doubt in its user. That's why, as the React team admits, "even between experienced React developers [there's disagreement]"

Again, there's basically one way to make components since not many are using classes anymore. React is a "library" not a framework. It's not Angular, or Knockout, or Ember (by the way how are those doing) that does the "batteries included" monolithic approach. 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. Let's not be dramatic and act like all the other web communities are 100% on the same page with every single thing. React just lets us choose the tooling that goes on top of React for different architectures. That's a good thing. And by the way, the "disagreements" mean that there's discussion and the best ideas rise to the top. This has not been the case for the monolithic frameworks.


I stopped reading about there because like I said in the comments, practically every paragraph had wrong or misleading information.

We all have different tools like we like. That's cool πŸ‘ You don't have to like React, I don't mind that. But there were many falsy or misleading things and beginners who don't know any better read this kind of stuff.

Top comments (12)

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.