Really, why React?

NOTE: I wrote this more than a year ago and decided to not publish it. I’d rather focus on writing constructive stuff (ok, and because future hiring managers might be React die-hards haha!).

But today I reviewed a candidate’s take-home that made me c…


This content originally appeared on DEV Community and was authored by Jordan Brennan

NOTE: I wrote this more than a year ago and decided to not publish it. I'd rather focus on writing constructive stuff (ok, and because future hiring managers might be React die-hards haha!).

But today I reviewed a candidate's take-home that made me close my laptop and go take a shower. It was 10x over-engineered and the worst part was it's all "correct" according to modern React! I immediately came here and published.

I recently got back into React since it first came out and I'm wondering all over again why someone would choose to use this library. Ironically, it's the React team's own words that reaffirm my aversion to it:

We’ve often had to maintain components that started out simple but grew into an unmanageable mess of stateful logic and side effects.
https://reactjs.org/docs/hooks-intro.html#complex-components-become-hard-to-understand

That's the opposite result of what has been so heavily marketed and promoted, and this is coming from Facebook's own engineers. If React doesn't help Facebook avoid an "unmanageable mess", then who does it help? React projects I've worked on aren't much better than the old jQuery spaghetti apps of the past. "But hooks can fix this!" Meh, more of a band-aid than a fix and it's just one of many issues I have with React. Here's my beef:

  • Excessiveness
  • JSX
  • Too many options, patterns, ideas
  • Synthetic events
  • Styles
  • DX is lame
  • Lack of respect for web standards
  • Over-engineering is normal, even encouraged

Let's start with excessiveness...

Excessiveness

I crave tools that simplify my work. If linking to a library, opening its docs, and using standards-based code doesn't work, I'm 98% less interested in that library.

jQuery, for example, required nothing but a <script> tag. The same used to be true for Bootstrap. Today, it's yarning (because npm is not cool enough) and CLIing for an hour before you get to use the thing.

I'm not convinced modern ideas can't be implemented in a way that delivers the amazingly simple experience of the past. Polyfill.io is a good example of a modern use case that avoids the excessiveness of Babel/Webpack polyfills. Frameworks like React should be easy like that.

JSX templates

Instead of HTML or template literals, React templates use, according to the docs, a "funny tag syntax [that] is neither a string nor HTML." This non-standard syntax results in not-so-funny PHP- and JSP-like code. What is funny though is JSX was added as a way to avoid using React's own createElement API. What kind of library adds one weird solution so you can get out of having to use their other weird solution?!

A lot of the template code you would expect to write you can't because "React DOM uses camelCase property naming convention instead of HTML attribute names." 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="">.

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

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

SVG code can't have namespaces or else "React's JSX doesn't support namespace tags."

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.

I'm certainly not a proponent of using the style attribute, but this is just another ridiculous speed bump in my work.

Hopes for changing all the funny stuff have come and gone (see https://github.com/facebook/react/pull/10169). What happens is developers come along expecting to use their HTML knowledge inside React templates - understandably so - and slowly realize how far off JSX really is, and so they of course expect it will get fixed. But the jokes on them! JSX isn't broken, this is by design and is unlikely to ever change unless React introduces a JSX replacement that actually supports HTML.

There's a bunch of these JSX gotchas buried in the docs and I guess this is just one of those things you have to...what exactly? Really, what do developers honestly think of JSX?

Another very big departure from HTML is JSX can pass content to attributes. From the docs:

return (
  <SplitPane
    left={ <Contacts /> }
    right={ <Chat /> } 
  />
);


function SplitPane(props) {
  return (
    <div className="SplitPane">
      <div className="SplitPane-left">
        {props.left}
      </div>
      <div className="SplitPane-right">
        {props.right}
      </div>
    </div>
  );
}

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. What a bummer that so many millions of lines of JSX have been written and will not be portable once JSX goes away!

So, to summarize templates in React:

  • Use the funny JSX syntax to avoid createElement
  • Your JSX will turn into a PHP-like "unmanageable mess"
  • You must learn a long list of JSX gotchas, which is worthless knowledge that doesn't actually help you accomplish anything or transfer to other libraries
  • Your template code will not be portable

Not funny.

Functional or Class-based, controlled or uncontrolled, forwardRef, mixins, HOC, Hooks, etc.

I'll let the React docs summarize this problem for me:

If you look at a typical React application in React DevTools, you will likely find a “wrapper hell” of components surrounded by layers of providers, consumers, higher-order components, render props, and other abstractions.

They weren't kidding when they said "unmanageable mess". I appreciate the honesty. Acknowledging you have a problem is the first step to recovery.

The fact that there are so many options and types of components confuses me. This immediately makes an engineer question which way is better? What are the tradeoffs? Perhaps one or more of these are getting deprecated?

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]" on just a subset of these options. It's scope creep and it's exhausting! I want simple tools, like a hammer. A hammer has just two options: pound nails and pull nails. Its design makes it obvious to the user which interface is used for what.

Anyway, React docs say "the simplest way" is functions:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

I agree. Nice and simple. But that doesn't address all the questions and concerns when presented with the Class alternative:

class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

To avoid reading too much into several contradictions in the React documentation, I'll skip to what I know: the differences between these two options are less now than they used to be since the introduction of yet another option: Hooks.

The docs say Hooks were introduced as a new way to solve for certain needs, like code reuse, and because higher-order components are too "cumbersome and make code harder to follow". For me this just adds to the chaos. Should I now do a function with a useEffects Hook or stick with a class and lifecycle methods? And what benefit do I get from picking the better option? Or maybe there is no better option and this is all a show and no one actually knows so everyone just quietly follows along?

In engineering - software or otherwise - when more solutions are added to address common issues in the original solution it's a sign that original solution was flawed. A big rewrite or abandonment is the inevitable outcome.

I recently read a React post that highlights one of these design issues:

In larger apps you may find that the components you're using to pass props down aren't even using those props at all, but need to pass them in order for children components to use the state.

That's a flaw of the original design and an additional solution - Hooks - was added as a way to deal with it. The original design of state in React was like using URL query strings for session storage. In order for state to persist through a user's session the query string would have to be explicitly passed on every navigation regardless of whether the next page needed those params or not. That would be a very error-prone and burdensome design, and yet that's the design React has. A better design would have provided a way to access state from a global context and that's one thing Hooks are trying to fix.

That's just function vs. class, there's still so many more options like controlled vs. uncontrolled. React's docs refer to controlled components as "tedious" and "annoying". I agree. So why not fix the underlying issues that created the need for these two options instead of adding more workarounds?

Like JSX, is all this mess just accepted without a second thought? Or are people simply tolerating it and moving on?

Synthetic events

Here's another one that just boggles my mind. JavaScript, which React and JSX are supposed to support, has the ability to dispatch custom events on any element. Like this:

// Create custom "bark" event
const bark Event = new CustomEvent('bark')

// Bind to the bark event in your render function
render() {
  return <div id="x" onBark ={this.handleBark}></div>
}

// Now make the div "bark" 
document.getElementById('dog').dispatchEvent(barkEvent)

Yeah, doesn't work with React.

This is because React has its own events implementation that isn't smart enough to support CustomEvents. Is not supporting core DOM technology normal? Developers are okay with React just not supporting some parts of the internet?

Fine, I'm not being fair. Yes, React can do it...you just have to use two other parts of React (componentDidMount and createRef) and not use the primary feature of React (render):

constructor(props) {
  super(props);
  this.x = React.createRef();
}

componentDidMount() {
  this.x.current.addEventListener('bark', this.handleBark)
}

render() {
  return <div id="dog"></div>
}

If JSX is funny, then synthetic events are hilarious.

Styles

When I find stuff like this https://github.com/airbnb/react-with-styles I just have to wonder what other devs think. That's A LOT of API to learn just to get some styles; to make CSS work lol! Are we sure this problem hasn't been completely overthought or does React really need this kind of nuclear-scale solution to make CSS work? I don't think it does, but sheesh! there's 62 ways to do CSS-in-JS, so somebody thinks it does.

Meanwhile I'm over here with Vue and Riot getting scoped styles using real CSS:

// Vue component
<template>
  <button>Save</button>
</template>

<script>...</script>

<style scoped>
  button { background-color: lightblue }
  button:hover { background-color: blue }
</style>


// Riot component
<my-component>
  <button>Save</button>

  <script>...</script>

  <style>
    button { background-color: lightblue }
    button:hover { background-color: blue }
  </style>
</my-component>


// Pre-processors are easy too
<style lang="scss">...</style> // Vue
<style type="scss">...</style> // Riot

Developer Experience

No, React is not "just JavaScript" as advertised. In fact, it is so far from it you can't even debug your app without installing special React tools:

"Download the React DevTools for a better development experience"

I think that message from the logs should read:

"We're sorry, but out-of-the-box the React development experience is broken. In order to make it usable you'll need to stop what you're doing and install our browser plugin before you can debug."

Better install the Redux extension while you're at it.

And don't forget that JSX plug-in.

Oh, and you'll need to set up a build pipeline before any of this is even going to work. Better yet, don't even install React. Go get the create-react-app CLI and use that.

Once you have things working, you still run into ridiculous speed bumps when trying to implement the most basic things, like Google Tag Manager.

Meanwhile Riot.js (and others) is instantly usable from a CDN and actually is "just JavaScript", so you can debug your app and inspect the DOM as you normally would.

Standards, portability, and over-engineering

HTML, CSS, and JavaScript are web standards. They will outlive every framework, library, service, preprocessor, syntax, bundler, pattern, corporate-sponsored open-source project, and over-hyped fad that comes along.

When you write JSX and CSS-in-JS you are laying down code that can't be picked up and ported to a new stack. This is a major drawback of any framework that encourages these non-standard solutions. I heard a really good piece of advice from a developer friend who said, "Pick a framework not because it’s popular, but for how much of a legacy mess will be leftover when it’s not." There's a lot of wisdom in that. A great framework is loosely-coupled and respects standards. If you want to change parts of it, or all of it, you should be able to do so without a complete rewrite. Good design works that way.

I think React is one of the worst offenders and one of the worst areas for portability are React functional components because they're basically used as a way to dynamically render HTML or a string. JavaScript template functions are a dependency-free standards-based solution for doing the same thing! On the surface there's only a 3 character difference between these two code snippets, but in reality they are worlds apart:

// Don't
function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

// Do
function Welcome(props) {
  return `<h1>Hello, ${props.name}</h1>`;
}

Even basic stuff like <textarea> has been messed with and can't be ported:

<textarea value={this.state.value}/>

Versus everything else

`<textarea>${value}</textarea>`    // JavaScript
<textarea>{state.value}</textarea> // Riot
<textarea>{{value}}</textarea>      // Vue
<textarea>{{value}}</textarea>     // Handlebars

It just kills me to not be able to use real HTML with React.

What's just as crazy is even when HTML works as expected, the React docs suggest you start with "a small component like Button." Components like that are bad engineering. Button, headings, anchor, and the other 100+ HTML elements should not be recreated as React abstractions! Reasons include:

  • Doesn't respect standards
  • Wasted effort on re-inventing what already exists
  • Needs custom documentation
  • Adds unnecessary point of failure
  • Needs tests and adds test execution overhead
  • Adds browser execution overhead
  • Bloats your bundle
  • Can't be used by non-React apps

The next time you see something like this (it's a real code sample btw) just run away and tell an adult:

<Link href="/about">
  <a>About</a>
</Link>

A popular React framework recently announced:

Applications can now directly import .css files as global stylesheets.

This is ridiculous. One tiny line of regular HTML does the same thing. The React current has been slowly drifting people further and further away from the web platform into deep over-engineered waters.

Performance

The React docs say, "No matter how good a UI library (such as React) might look on a benchmark...a certain amount of work in your components will always cause stutter." Whoa, React used to brag about how insanely fast it is and how the virtual dom, one of React's fundamental technologies, makes it all possible. Now there's unavoidable stutter. Then Svelte and Riot showed how a vdom and its issues can be safely avoided and increase performance.

Performance of a library is always a bit too subjective, so I look at how does that library impact the overall performance of my app. Is the library big, like 10+ kb big? Does it tend to require a lot of extra dependencies? Does it demand a lot of idiomatic abstractions or does it get out of my way and allow for vanilla js? Does it add to the complexity and finickiness of the build process? React is the ultimate complexifier and in this way I find its performance to be unbearable.

Bonus: StrictMode

When a framework has to introduce special “modes” to help you navigate the bad stuff, it’s done. Burnt. End-of-life. Time to cut it loose and push it out to sea.


This content originally appeared on DEV Community and was authored by Jordan Brennan


Print Share Comment Cite Upload Translate Updates
APA

Jordan Brennan | Sciencx (2021-08-04T04:36:26+00:00) Really, why React?. Retrieved from https://www.scien.cx/2021/08/04/really-why-react/

MLA
" » Really, why React?." Jordan Brennan | Sciencx - Wednesday August 4, 2021, https://www.scien.cx/2021/08/04/really-why-react/
HARVARD
Jordan Brennan | Sciencx Wednesday August 4, 2021 » Really, why React?., viewed ,<https://www.scien.cx/2021/08/04/really-why-react/>
VANCOUVER
Jordan Brennan | Sciencx - » Really, why React?. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/08/04/really-why-react/
CHICAGO
" » Really, why React?." Jordan Brennan | Sciencx - Accessed . https://www.scien.cx/2021/08/04/really-why-react/
IEEE
" » Really, why React?." Jordan Brennan | Sciencx [Online]. Available: https://www.scien.cx/2021/08/04/really-why-react/. [Accessed: ]
rf:citation
» Really, why React? | Jordan Brennan | Sciencx | https://www.scien.cx/2021/08/04/really-why-react/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.