React Won by Default – And It's Killing Frontend Innovation
48 points by dbushell
48 points by dbushell
I’ll say this as a full-stack dev who is now in a mostly frontend role programming React daily: there’s vast amounts of overuse of JavaScript frameworks. There’s very little value to more frameworks if what they’re giving us is just reinventing native HTML semantics, which is what 80% of React code in the wild is doing.
The innovation these frameworks have given us has been mostly related to three things: reactivity (two-way binding mostly), state management and component reusability (more specifically declarative templating). More focus should be given to bringing those functionalities to Web standard APIs.
Web Components already exist, but they’re slightly annoying you use. You’ll likely still need a library wrapper to make it comfortable. They should 100% try and make using it more ergonomic.
Signals (Reactivity) is already a proposal. After that’s added, these libraries add nothing worthwhile imo. You don’t nee true SPAs, you can use the browser’s native view transitions and rely on the browser’s caching and component injections to achieve 99% of what a web page should do. There’s very few websites that really need pages that change so much that they need a library to manage the state changes for them.
Unfortunately Web Components are more than just slightly annoying to use, some things are just not possible with it currently. Passing attributes to children in templates declaratively, for instance.
DevX matters a lot for adoption. Two-way binding and declarative templating should be much easier and having just that is a huge plus for JS frameworks’ dev experience. Simple things like attaching an event handler in a Web Component are harder than they should be and that alone will push people into something that offers on:click={foo}
.
I hope we’ll get there one day, but most of the focus I see are on relatively niche things that require other things for adoption, e.g. who cares about Signals if there’s no clean way of using it in a Web Component’s template.
Passing attributes to children in templates declaratively, for instance.
When I discovered you could only pass string attributes to children it was such an epiphany: web components are great at sprinkling a little bit of JavaScript on a single html element with 0 dependencies but anyone who would even compare them to web frameworks is unserious.
Yeah web components are cool for completely self contained components, but applications are rarely composed as a bag of entirely unrelated entities
Yeah, for sure, they are not designed for composability at all. Not with each other, and not with existing HTML elements.
EDIT: FWIW I’m hopeful that will change. There are some good github issues in standardization world where smart people are trying to make this better.
Oh cool, mind dropping links to some of those issues?
Sure! Checkout the GitHub links at the top of the mdn documentation for the “is” attribute: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/is
The “is” attribute is dead in the water, blocked by Safari, so people are trying to find another way to make custom elements that extend built-in elements, eg a Button web component.
Which I have to say I thought we all learned from the failure of Java applets to take over the web
Simple things like attaching an event handler in a Web Component are harder than they should be and that alone will push people into something that offers on:click={foo}.
Ironically, though, this is also a pain point in React, in that if you write this one of the obvious ways like <Foo onclick={() => handleClick('xyz')}/>
, it appears to work just fine, but you’ll potentially end up with unexpected re-rendering of part of your page because the arrow function is instantiated from scratch each time and React thinks it means the component’s properties have changed. So you have to wrap it in useCallback()
which clutters the code with noisy incidental complexity.
…you’ll potentially end up with unexpected re-rendering of part of your page because the arrow function is instantiated from scratch each time and React thinks it means the component’s properties have changed.
It also reinforces the author’s point. This is not a problem one has to worry about in, for example, Vue.
For me, the true cost of those useCallbacks is the cognitive overhead of remembering to use them and manually list out data dependencies. I don’t believe in practice the performance impact has ever materially effected the apps I’ve worked on
This issue is what gave me so much trouble with React when trying to use (not learn) it recently. Similar arbitrary mental overheads like needing to always return the same number of hooks called in the same order, or some such issue, is why my vibecoding would eventually lead to infinite loops (fail to render) and insanely slow loads out of nowhere. The loops I struggled to figure out with debug tools, ended up falling to printf debugging. I only managed to wrangle it under control for good when I found zustand by describing how I wanted the data model and the React rendering so thoroughly separated that this sort of React-caused issue would become impossible.
I can believe that it becomes invisible to experts, but I am not one, despite starting with HTML For Dummies in the early 2000s and being a full-time (backend?) programmer.
And it completely reinvents the wheel of event propagation that already exists in the DOM.
Needing to useCallback is less pain than using events with web components.
Also, your example should just be a performance hit, you can prevent it with linting, and the react compiler fixes it.
mostly related to three things
If we’re talking about fundamental tenets, I’d like to suggest adding “identity” to your list. Most of these frameworks try to establish a declarative relationship between state and representation. It’s so much easier to think of the front-end as a function state -> UI layout
, but the reality is that many important UI components have internal state that is too hard or impossible (due to not being exposed by the platform or libraries providing them) to lift to the framework state
, and this problem is swept under the rug by doing some ad-hoc best effort to maintain the identity of the “physical” components and their abstract UI layout representations when possible.
IME this identity management problem is where the current frameworks all start to crack and leak and your front-end architecture will also get stressed the most at the points where it touches the identity problem. It’s also interesting how different FE frameworks from different paradigms deal with this problem, but it’s invariably a tough knot for all of them.
On the contrary, I’ve found that to only really be the case for React. Other frameworks tend not to lean so hard on the state -> UI
paradigm, which means they largely avoid the problem. In particular, I find signal-based frameworks (which at this point is most of them apart from React) tend to handle platform state quite well, because they rely on components themselves being stateful objects. In that model, HTML elements with their own state are just components created by the browser. You can set their properties just fine (value={...}
means that every time ...
updates, the value
property will be updated in turn), but you can’t expect to control their entire internal state.
There’s very little value to more frameworks if what they’re giving us is just reinventing native HTML semantics, which is what 80% of React code in the wild is doing.
As the article points out, React’s API design leans heavily on data immutability, creating an enormous performance bottleneck. At the time it was first released, there was a lot of enthusiasm for writing JavaScript as if it were a purely functional programming language. It is not. One can use functional patterns here and there with negligible performance costs, but as the basis for a framework, that decision has not worked out well. React has been significantly slower for years than frameworks that use getters and setters (e.g. Vue 2), proxies (e.g. Vue 3), or compiles to imperative JavaScript (e.g. Elm or Svelte). There have been some features added here and there you have to opt into that eek out some modest performance gains (concurrent—not parallel—rendering, deferred rendering, etc.) that don’t solve a fundamental design problem. There is also lots of room for innovation in sharing code between pre-rendering, server-side rendering, and client-side rendering, as evidenced by metaframeworks.
A lot of their value, IMO, is (or was) in their polyfills, also. If you use the react version, you get all the browser support the framework maintains for nothing more than the cost of using the framework. So if you were using the reactivity already, the overuse bought you a consistent API for everything else.
That’s not nothing, and I’d almost hesitate to call it “overuse”. Getting a consistent API across all the browsers you care about is a valuable thing. Obviously React isn’t necessary for that, by any means. But if you’re already using it for those 20% things you mention, you might as well take advantage.
Interesting observation. That was also (often) a reason for people to use jQuery back in the day.
The article does not quite phrase Svelte the way I would; the way I would phrase it is that Svelte is free. There is no runtime framework overhead; there is no pile of abstractions bloating your deployment size and execution time; there is no non-portable marrying of execution and structure. The moment you need any JS-constructed part of the page at all, consider Svelte, because it makes everything better for free. Even when web standards evolve to include part of what Svelte does, Svelte still does it more succinctly, which means you should use it because it’s free.
Although I quite like Svelte I disagree with saying it’s “free”. There’s build overhead which makes it very distinct from JavaScript as an augmentation language.
I can’t drop a Svelte component anywhere without going through a build step first, at which point it’s unreadable for humans. It is also a deployment overhead, a big one at that because it fundamentally changes how you deploy both CSS and JS.
I’d like to have the things that Svelte does, its compiled code that handles updates, exposed as an API in browsers free of build step or extra tooling.
This isn’t a purist take but that is what we’ve always done with improvements to Web standards. We used to need preprocessors for CSS nesting, now it’s native. I want to be able to say “we used to need Svelte for this, now it’s native”.
You already have a build step, unless you’re using the most brick-simple Django setup possible. Maybe JS didn’t previously integrate with it but it really does not add much complexity to the single ‘spin up the everything’ command. ‘Unreadable for humans’ is kind of silly imo, we don’t evaluate desktop development languages that way but if you want a sourcemap it’s only a few extra lines of config.
For the purposes of your webpage acting as a webpage to the end user, Svelte is free.
I think part of the issue is that there was reasonably broad consensus around what CSS nesting ought to look like before it was introduced as a standard. But for web frameworks, there’s no real consensus. Should templating be done with a specialised templating language, with JSX/h, or with template strings? Should state management be signal-based, event/stream based, or attached to components? Is the VDOM a useful abstraction, or is it too leaky?
There are some things that are slowly becoming consensus. For example, signals are generally considered good, and there’s a proposal to include them directly in JavaScript, although it’ll probably take a while to iron out those details. At that point, it’ll be fairly easy to implement a SolidJS-like microframework just by adding your own preferred way of generating DOM nodes. But I don’t think there’ll ever be much consensus on, say, templating, and I don’t think it makes sense for the browser to bless one style of templating as the “chosen way” when there are so many different options.
To be honest, I don’t like “frontend innovation”. The framework wars weren’t good or productive. React is pretty good, it allows me (a mostly systems, embedded, back-end and microcontroller developer) to express whatever front-end things I need relatively cleanly (at least compared to the DOM manipulation soup I used to write).
If anything, I wish React would slow down and become a more boring, slower moving technology that never breaks my stuff when I upgrade between versions.
But I think there is an over-use of React for situations where server side rendered pages would be more appropriate. (Reddit does not need to be a React app, and neither does your blog.)
Reddit does not need to be a React app, and neither does your blog.
100% agree, GitHub is a perfect example of a website that’s entirely page-based and should be driven by SSR, with a little bit of progressive enhancement for browsers with JavaScript (it’s nice that liking å comment doesn’t reload the page for example).
But React is not what makes any of them slow, so these are pretty bad arguments.
But sure, a blog is most definitely not the target audience for SPAs.
I think there is a fair argument to be made that react enables poor practices to flourish at the expense of DX.
I totally agree here as someone with a bit more focus on the frontend with a generalist background. The paradigm of functional reactive UI programming seems pretty figured out, at least nearly identical even across languages like clojurescript or elm. Yet the react API churns quite a bit year over year, mainly due to optimization strategies that I’m not sure most apps will require. But I haven’t stayed that up to date with it
It’s also infected recruitment, full stack now seems to mean react on the front end - and node on the back end.
I hate that idea of full stack. The term itself is already bad (very few people are just as good at both) but a PHP developer using HTML/CSS is as much a full stack dev as one in a JavaScript-only stack.
This seems silly to me. I dislike the term “full stack” because we used to just call this “a developer”. There’s no reason someone can’t do both and more besides.
I dislike the term ‘full stack’ for a different reason, namely because that’s only a tiny, tiny part of the stack. There are true full-stack engineers out there, meaning from JavaScript down to C/Assembly or even the physical layer. That’s also what the stack used to mean, before it was co-opted by web devs. ‘Full stack’ is a myopic view cemented in language.
I agree, to me what’s important is that we understand how the systems work at both ends. But what seems to actually be important is that you know enough to modify existing code without needing to understand the fundamentals.
I don’t know how this is functionally different from LLMs, maybe this is why some businesses think we can replace engineering.
I mean, that is a full-stack developer, and it’s probably the most common way to be full-stack since it doesn’t require as much diverse knowledge. But it’s a bit sad if the term has now been so entrenched that it excludes developers who master (say) Elm and Python.
That’s exactly what I mean. The requirement in many cases is simply to have react. All other considerations secondary, crew expendable, etc. The Australian job market may be biased, but that’s been my experience so far.
By coincidence, I’ve just today started a front-end project and I chose Svelte. Last time I just used old-style server-side templates and some jQuery, but I’ve decided to join the modern age.
My lazy preconception is that a lot of web devs don’t have a solid CS background and just learned on the street, so they feel less secure about DIY and are more likely to choose what they already know or what ‘everybody’ else is using.
a lot of web devs don’t have a solid CS background
I don’t think having a CS background or not has much to do with it. Pretty much all the recent CS grads I work with are familiar with React but struggle with basic web stuff, like forms.
I’m talking about knowledge of computer science principles, not a particular university degree. It’s about learning how to learn new things, by knowing the underlying concepts.
A university that teaches CS students React seems more like a vocational school — it’s like if they had a Mechanical Engineering degree that just taught you how to repair car engines.
To be clear, I don’t think any of the people I mentioned learned React in school, they learned it in the one or two years between graduating and joining my team, on the job. I’d agree if they had that’d be more akin to a vocational school.
I think we agree on the principle, but what I’m saying is that I don’t think CS fundamentals (regardless of how you picked them up) help that much here. CS and engineering are different disciplines and evaluating architectural complexity is more on the engineering side.
I think we agree. I also think there isn’t really such a thing as “Computer Science”. There is computer engineering, which is most of it, and computer mathematics for the fundamentals and theoretical stuff.
(I do think debugging is a science, but there’s a separate branch of it for each program anyone debugs, so it’s not a field of study in itself.)
I see what you’re saying and while I’m not able to disagree with data, I would suggest that this is the case for pretty much any entry level developer - people use the tools of the trade before they’re really good at judging their value. I guess this general attitude irks me a bit because it is so often used as a way to belittle junior front end developers (not saying you specifically mean to do that!)
This article has decent points, but…honestly it’s not like this is webdev-only, right? Generally, any ecosystem will, over time, start to centralize around the main players. It’s not as if the competition is actually “dead” by way of React, either: you can see in the State of JS survey (though there’s certainly some volunteer bias here) that Vue isn’t too far behind in the space, and the aforementioned Svelte has certainly gained some recognition (Apple Music uses it!). But React is just still the default, because popularity usually becomes self-fulfilling everywhere.
I think it’s different - if you write a backend in Spring (be it Java or Kotlin), then some of your stuff is Spring but I feel like 80% of your code could be in any language.
If you have a React frontend then 80% of your code is React code.
It’s not even comparable. Ripping out Spring and adding any other framework for a small app is a day or a week, for the frontend it’s a 90% rewrite.
I think this really depends on what exactly the domain is. The average frontend that would require a 90% rewrite is probably largely a visual layer over some backend API, which means that the stark majority of the code is:
By contrast, the average backend API for this is going to spend most of its logic not in the controllers but rather in the data layer and business logic. That might still be tied to a framework though! If you’re, say, working on a Rails app, and you decide you want to switch frameworks including moving off of ActiveRecord…well if you followed “fat models” then you’ll probably be in for a hell of a rewrite. This is of course still ecosystem-dependent; I’m not super familiar with the Java world, but my limited understanding is that the framework and the data layer are usually pretty independent of each other, and you don’t usually tend to see “fat models” as much? (Though really I should add a disclaimer that I’m not exactly a Ruby dev either, I just know a bit more about that ecosystem by osmosis.)
A slightly different but maybe closer client example might be trying to move a networked Qt application that uses QtCore throughout and QtNetwork and all the related gizmos. That would probably require a 90% rewrite.
It may sound (and actually sometimes feel) overblown but I’ve mostly seen some form of hexagonal architecture the last few years, so in theory I could even reuse my incoming part (the HTTP), my domain model does not change, and then I need to rewrite my DB models. This is not a lot of work for up to medium services, usually.
I think Rails may be the outlier because to me the majority of Spring Java Backend code feels just like any PHP or Python framework, where I would handle http stuff, not expose ActiveRecord to the templating thing.
I think I agree that they’re not totally comparable, and I think it’s specifically because frontend web frameworks offer 1) an organization of data & control flow and 2) unique APIs for actually expressing the UI. Both of those are going to be unique to the framework.
Contrast to a backend web framework where the control flow of request-comes-in, response-goes-out is relatively uncontested across frameworks.
That said, it’s my experience that, in practice, applications are built in a way where they are married to the framework they were originally written in (liberal use of spring annotations, react hooks, etc.), and it’s hard to argue why they shouldn’t be, since replacing a framework is not something you will typically ever have to do.
I’ve felt the difficulty in getting a framework to get traction myself. That is in part on me or the framework - it is possible for new frameworks to gain traction, after all. But it’s definitely much harder once dominant options have been established.
It stood out to me how SolidJS users are described as early adopters in this blog post. I think the fact that SolidJS is held up as a relatively new thing is a nice illustration of how hard it is for new frontend frameworks to break through.
Here’s a bit of a timeline:
React went open source in 2013. So it’s been among us for 12 years.
SolidJS according to its changelog goes back to 2018. It’s been around for about 7 years.
I blogged about using SolidJS in 2022. I liked it; fit my brain better than React, which I had considerable experience with and also adopted early on, as it fit my brain better than the alternatives at the time.
At that point React had been around for 9 years, was very well established. So it was around just a few more years than SolidJS is now. But clearly it doesn’t feel that way. Nobody would consider a React user in 2020, when it was 7 years old, to be an “early adopter”.
It’s ironic that React, a framework so willing to break with assumptions when it was new, is now the dominant story people complain is holding us back.
That default is now slowing innovation across the frontend ecosystem.
Frankly, from my perspective, we have gotten to this point out of an over-abundance of “innovation”. To the point, as others in this thread have pointed out (and I realized I did a while ago) everything is so far abstracted that there is an entire generation of developers who don’t know better than that react is the way to do front-end. Something about “if all you have is a hammer”.
The same is true for a lot of often used front-end dependencies. All intended to make front-end development “simpler” and more “streamlined”. I am not saying we should go back to the days of jQuery (vanilla JS is to the point that it really isn’t a requirement anyway) or that we should drop all frameworks altogether.
But I honestly do feel that front-end development specifically has been chasing the latest shiny for too long at the detriment of stability and simplicity.
The author sort of makes a similar point, but at the same point basically recommends three different frameworks offering different “advantages” to just further fracture the entire thing. Do I think we need to stick with React as a default? Absolutely not, but I also do think the author is not seeing the forest for the trees. Basically, for a lot of development work, I feel like we probably should take a few more steps back.
Do I have a good solution in mind? Nope, I am not a titan of industry with a strong vision forward. I am just a random person on the internet rambling about the front-end insanity I have been observing for the better part of a decade.
At my work we use Angular and .net. I would be open to svelte, but I just know Angular so well and the rest of the company wants predictability.
Vue is one of the best frameworks imo, with its use of slots and models, both of which are essentially syntactic sugar. Its templating language is also pretty nice. React’s development seems to be keeping itself “barebones” in the component space but expanding in the “server” space. (Though some React frameworks have the slot pattern as well)
A core React maintainer’s take (a thread): https://bsky.app/profile/ricky.fm/post/3lyxjkguwic2q