The Dopefly Tech Blog

« The Dopefly Tech Blog Main page

React is Harmful - 25 Reasons Why

posted under category: General on January 4, 2023 by Nathan

I don't apologize for the clickbait title. I've worked on the web for over 25 years now. I've seen a lot of things come and go. I've seen good technology and bad, both win and lose.

Over the past handful of years, I've become less and less of a fan of React. The more I think about it, the more I believe that React is the worst popular framework (sorry, "LIBRARY") that exists. Let me explain why.

Prologue

React has been wildly popular ever since the Facebook engineering blog posted their first articles about it in 2013, explaining the need for state-driven interfaces and the flux data pattern. Ever since, React has been a pioneer in the lightweight JavaScript component framework space, incubating a lot of new ideas. React is so popular that it even makes job-hunting easier - when you read "React" in a job post, it signals a difference from the older generation of jQuery JavaScript apps.

I first learned React in 2016, when I was hoping to find something to replace jQuery - something that would let me add HTML templates in an integrated framework without another library like Mustache or Handlebars. Those were the best things I knew about at the time, though Angular would have probably sufficed. I was given the perfect application to branch out and try new things - an easy lay-up for a capable JavaScript framework. It seemed like everybody at the time was talking about React, so I should try it.

That's when I was blindsided by npm, node_modules, 8-trillion javascript packages that were all 2kb, and then the big ones - Babel.js and Webpack. I backed off and did it my own way for this project.

A year or two later, I found Vue.js, which actually solved all of my problems with React at the time. The following year, I was handed another project written in React. It was a SPA. I studied and learned, and I expanded it and helped stabilize what we had built, experimented with it a lot, pushed it to its limits, decided what I liked and did not like, became a company expert in React, and then realized that so much of it was too brittle to change and grow in a meaningful way, plus I... had the time... so I rewrote it in Vue - it took 7 days (even though thought I could do it in 5). Everyone loved the result.

The next year, I found myself with another React app, this time a much larger app with a team of developers and years of history. At first I was happy to nurse it along and add features until I got reassigned somewhere else, but then I started to notice the underlying issues. This one had serious architectural problems, reactivity problems, complexity problems, and performance problems, plus new features that would not be easy to add on. We decided to rewrite it, and I pushed my preference for Vue.js on the team. It took 6-9 months, but we made something scalable and capable that is much easier to work with. I will admit that most of my interactions with React have been bad applications, so that's where my rant really begins.

1. React is bad by default. A successful React application must be backed by very experienced developers. Newcomers aren't likely to fall into the "pit of success" - it's more like mountain climbing - you have to prepare, you have to bring a guide, you have to study your approach step-by-step. If this is your first time on the mountain, you won't summit.

2. React has a doctorate-level vocabularity. "Immutability" "Memoize" "hydrate" "Pure Component" "UseEffect" "Synthetic Event"

These are words come directly out of a DCS degree program but don't make sense to non-doctoral, even native, English speakers. It's not that this is hard to understand these words and concepts, it's that it's unfriendly - hostile even.

3. The Lifecycle Event vocabulary is just stupid. I'm glad that we have mostly done away with some classics like ComponentWillReceiveProps which was infinitely confusing, but shouldComponentUpdate or getDreivedStateFromProps - what are we doing here? To contrast, Vue.js simply has beforeMount and mounted, beforeUpdate and updated, and so on, while Svelte has onMount, onDestroy, beforeUpdate and AfterUpdate.

4. Hooks are yet another brainiac term that are contextually unclear. Hooks somehow simultaneously do everything and nothing. They replace state and they are the new event system and they are the easier way to cache things and they are the best way to debug everything. But how do they work? And why? Only little explanation is given.

5. Why do hooks have to be the first thing in a component? This feels like a code smell that indicates poor design.

We're going to hear this a lot: Let's compare it to Vue. Vue implemented a hooks system, but they took out the odd placement requirement - you can put them anywhere in Vue.

6. When we add Redux, we add more vocabulary problems, specifically the way Redux redefines words incorrectly, for example

  • Action - A tiny data structure that doesn't do anything (not an actual action)
  • Reducer - unintuitively, changes the state (immutably)
  • and Dispatcher - a useless convention to do a switch/case with actions for some reason

7. When we use Redux, or any state mangement library that loosely follows the Flux pattern, immutable state creates many copies of our state in-memory. A lot of state changes at one time will run up our memory usage very quickly and cause additional garbage collection, which may happen at any time, and can affect the performance of our applications.

While an immutable state avoids a number of problems, and may solve some very complex concurrent data issues, a large immutable state is a problem on its own.

8. If we added Redux to an app before 2020, we absolutely need to have added Thunk and Saga for asynchronous operations, then Reselect to "memoize" (or, cache) the Selects from the global state, plus Immer to shrink our reducers' scope. None of this is documented of course. None of this is official. You'll only see it if you read the right blog on the right day, but this information is basically required if you want your app to work the way you expect it to.

9. If we added Redux after 2020, we would absolutely need Redux Toolkit (unless you're a sadist), which of course has its own additional vocabulary.

  • A Slice - sort of a module of the state with selects and reducers all-in-one
  • AsyncThunk, EntityAdapter, I'm not even sure what these are

Redux toolkit makes Redux a lot more manageable but adds more overhead, both physically (in bytes) and mentally.

10. Redux, and all flux-patterned global state management systems add an incredible amount of complexity.

Complexity adds bugs, so this is a simple formula: reduce complexity to remove bugs. Remove Redux to reduce complexity. Therefore, remove Redux to make better applications.

But of course we need some kind of global state management. Therefore, we should all be looking for the simplest solution to reduce our bugs. Even though Redux is the most-default-looking choice, we should shop around. Instead of Redux, try MobX, or Recoil, XState, Hookstate, Akita, ClearX, Rematch, or any of the, roughly, 50 different great choices available.

11. And that brings us the problem of choice. React has no default path to success. There are no "easy" decisions. Every choice presents fifteen options, none of them advantageous over the others; every library needs seven more; each choice Fractally branches out to infinity, with options forever.

12. React is bloated.

  • If you add React + React Router + Redux + (reselect+thunk+immer) + React DOM, you get about 300kb of framework files
  • If you do the same for Vue, which BTW is just Vue + Vue Router + Vuex, it's only 100kb
  • If you do it for Svelte, it's essentially 0kb (not in reality, but Svelte is like a kind of magic)

13. React carries around features that only Facebook wanted to add. For instance, no one else was interested in...

  • "Concurrent Mode" - billed as interruptable UI re-rendering
  • "Portals" - Which I think finally went into production; it renders a component somewhere else in the page
  • "Transitions" - Which are supposed to help with loading new content
  • and "Suspense" - Which creates a framework-preferred way of building a "loading" state for components

14. React is slower than Vue and Svelte and a number of other comparable, very capable choices. It uses more memory. It takes longer to start up. This is measurably true in Stefan Krause's "JavaScript frameworks benchmark" which he publishes every month-or-so, in sync with Chrome updates.

Don't freak out, React is still fast and it does a lot of things well. It just isn't the fastest, most powerful, most scalable thing out there. Not by a long shot.

15. React-DOM is a separate library. Imagine me, a veteran web developer, attempting to add React to a web page. Yeah. It turns out React doesn't do anything unless it can interact with the DOM through a second library that weighs in at 20x larger than React.

I do understand why it's separate - it's because the external-facing parts can be swapped out to interact with something that's not a web page, such as a mobile app. That doesn't excuse the fact that this is confusing, unintuitive, and probably not the best solution possible.

16. I can't just add React to a web page. I would have to add React, and React-DOM, and then a way to translate JSX to HTML and React to JavaScript, so that requires Babel.js plus a huge bundle of plug-ins specific to React and JSX. They say you can do this in under 10MB but I've never seen it done in under 30MB. Imagine serving a 30MB JavaScript application only capable of outputting "Hello World!"

The reality is, we also need Webpack to bundle and serve our React app, and the easiest way to do that is through the React CLI. To contrast this, by the way, we can add Vue to a web page with a script tag like jQuery and just start using it.

17. The React CLI is powerful, but limited, and breaking out of those limitations requires us to eject our applications from the CLI. Ejecting from the React CLI is a one-way operation, and it leaves us with a 2MB (or more) webpack.config file - these are usually around 1-20kb - this 2mb size is unmaintainable and impossible to work with. While it could be a testimony to how much React CLI is doing for me under the hood, the reality is that it's inconsiderate.

18. Code-splitting is a nightmare. Who of us have attempted to split our webpack chunks with React? Code splitting is an amazing performance enhancement that can cut down the initial download and processing our users have to go through, letting them download the rest of the app as they explore it. And for some reason, this was hellacious for me, multiple times, in multiple applications, over multiple years. This caused big problems trying to make my React applications more scalable. Again compared to Vue: Vue makes this trivial.

19. With React, you either choose JSX or pain. No one in their right mind would code an application with React.createElement() instead of JSX. A lot of the benefit of React is the way that JSX integrates. JSX is the default templating engine, the only templating engine, and there are no other choices. It feels like an OK thing because JSX is passable, but it also feels a little bit like vendor lock-in. Switching templating engines is not something that people do in React, however it's something we can do in Vue, and in a lot of other frameworks.

20. The reason I bring up our inability to switch from JSX is because JSX sucks. For instance:

  • To add a CSS class to an HTML element, we have to call it className="" - this is the cause of a lot of errors I've seen (and caused).
  • Similarly, the <label> tag's for element is illegal, we have to call it htmlFor - it's ridiculous to me that HTML is invalid by default.
  • JSX is XML. I thought we fought the good fight and squashed most of the XML in the world, but here we are again.
  • CSS with JSX is such a problem that there are 63 CSS-in-JS frameworks for React!

21. React state properties are not really "reactive." When we change the state through an official means, like setState or through a useState hook, React re-builds the entire component, and potentially the component tree. Of course virtual DOM will keep the screen painting as small as possible, but still component re-rendering can be expensive. Instead of saying that properties are reactive, I would say that state changes in React are overreactive. Again, when we compare this to Vue, every state change is immediately, minimally, and truly, reactive.

22. In 2017, a potential change to the React "OSS" license could have allowed Facebook to revoke the ability to use React to anyone they wanted; imagine writing 6 million lines of code in React and then being told we can't use it anymore because someone violated their policy. That's a game over. It's a bankruptcy waiting to happen. Of course FB recanted the whole idea, but there's still a strange potential for something like this, isn't there?

23. The Other Facebook Dilemma - if Facebook wants to change something in React, they just will. Companies - even huge ones like the one where I work - have no say in the matter. Conversely, if you need a feature changed in React, it's not likely to happen.

If you need a feature changed in a smaller ecosystem like Vue or Svelte, I guarantee that a healthy donation can move a lot of code.

24. I dislike how so many JavaScript programmers, especially those less experienced, treat React as if it's the only way to write JavaScript now, like there's never been another way. Does anyone remember how annoying it used to be that every JavaScript answer on StackOverflow started off by suggesting jQuery? We are close to a similar place with React today.

I do not want less experienced programmers to think React is the way JavaScript works, or the way all programming works. The world is so much bigger than React. React is not the best choice for most things, and I hate seeing people choose it without thinking through the options. You can do better. We can all do better!

25. We tell new developers that JavaScript is easy, then we give them React, which feels kind of easy, but then they get NPM, JSX, Redux, Typescript (which I actually do enjoy but the ecosystem of adding a transpilation step to JavaScript is a big one to swallow). JavaScript really should be easy, and React really is the opposite.

Epilogue

I think we all owe it to ourselves, and especially to all the new programmers out there, to stop choosing React as the default. There are plenty of occasions where it may be a good choice, but I don't think it's very often.

What do you think? I bet that if you've been a fan of React, this is pretty inflammatory, isn't it? I admit, I probably don't know as much as you do on the subject.

On the other hand, you may be sick of seeing React everywhere like me. In that case, you're probably thinking of a few more points I could have brought up.

Whether you're seething with rage or want to pat me on the back, feel free to drop a comment or tweet me back. I'm looking forward to hearing from you.

(Tweet back on Twitter)
Nathan is a software developer at The Boeing Company in Charleston, SC. He is essentially a big programming nerd. Really, you could say that makes him a nerd among nerds. Aside from making software for the web, he plays with tech toys and likes to think about programming's big picture while speaking at conferences and generally impressing people with massive nerdiness and straight-faced sarcastic humor. Nathan got his programming start writing batch files in DOS. It should go without saying, but these thought and opinions have nothing to do with Boeing in any way.
This blog is also available as an RSS 2.0 feed. Click your heels together and click here to contact Nathan.