React has grown beyond its original promise and it's causing more harm than good
md.jtmn.dev
md.jtmn.dev
This is a very common misconception. React was meant to provide one-way data flow. With an app built directly on the DOM you have to deal with the DOM having its own state to manage on top of the state your own code is storing. You have a list of comments in a variable, and a list of DOM elements for each comment, and nothing but your own code is making sure they stay in sync with each other. React changed things so that the state of the DOM is always derived from your own app's state, which eliminates what turned out to be a pretty tedious and error-prone amount of work in complex web apps.
It wasn't the first to provide this but its API was unique and compelling vs existing alternatives. The virtual DOM, server-side rendering, etc. are not things that make React faster than non-React code, they are things that counteract the inherent slowness in React's design to make it competitive with non-React code.
Watch the original JSConf talk where React was publicly announced and released, and notice how the talk is mostly about the one-way data binding, and the virtual DOM/reconciliation are mentioned in the back half as ways React catches up to non-React app speeds: https://www.youtube.com/watch?v=GW0rj4sNH2w
I'm not sure that's true in general.
For example, for some tools there's no single 'one level abstraction below'. Let's take regular expressions as a simple example. You can use them effectively, no matter whether your regular expression matcher uses NFAs or Brzozowski derivatives under the hood as the 'one level [of] abstraction below'.
(Just be careful, if your regular expression matcher uses backtracking, you might get pathological behaviour. Though memoisation makes that less likely to hit by accident in practice.)
A better example might be that of a compiler, where you (very rarely) need to look at the asm output or encounter a case where the compiler generates incorrect code and you need to debug why.
Nope, that will never happen to me. No regular expression has that behaviour.
There are some bad implementations of regular expression matching that have these problems for some regular expressions. But you can avoid those bad implementations without understanding anything.
> I encountered one a few months ago, so it’s not at all uncommon or difficult to encounter.
That only happens, if you use a regular expression matcher that uses backtracking. Sane regular expression matchers take linear time on all input strings.
> If you’re curious enough, you’d end up reading about how regexes work under the hood.
There's no one single way regular expressions work under the hood. You had the misfortune of using a matcher that uses backtracking and is prone to catastrophic exponential runtimes.
There's multiple different ways to implement regular expression matchers. But a user doesn't have to care or understand anything (they just need to avoid the buggy ones).
Sure, if you read up on how regular expressions work under the hood, you can learn to avoid those bad matchers. (Or you can learn how to live with your batch implementation, if you are feeling masochistic.)
But that's entirely optional: You only need to read one blog post that tells you to use grep and avoid eg Perl. You don't need to understand why backtracking is bad for regular expression matching; as long as you avoid those bad matchers.
Regular expression libraries that don't use backtracking are available for many languages. Yes, some languages have bad libraries that use backtracking, too. But bad libraries will always exist, they aren't an excuse when there are more good libraries around then ever before.
In fact it wasn't necessary for me to qualify that with "I would say". I do say, and it simply does. You've made exactly no argument this entire thread.
Maybe everyone doesn't need to know everything, but the skin of stuff anyone needs to know is thicker than 0, and has no absolute boundary layer either, you just generally need to know less the further from your own work. But that never goes all the way to 0. You have to rely on other people to have done their jobs, but you still at least have to understand what those jobs are, that they exist and how you ultimately interact with them and how they impact you.
You said so yourself several times which makes this all farcical.
Doesn’t that exactly demonstrate why using the tool effectively requires an understanding of the implementation (or possible implementations) behind the abstraction?
You can just consult a list that tells you which regular expression matchers to avoid (like eg Perl), and which ones are good (like grep), and you are good to go. No need to understand anything.
You can just consult a list that tells you which regular expression matchers to avoid (like eg Perl), and which ones are good (like grep), and you are good to go. No need to understand anything.
Unless you're coding in Perl or sed or whatever then regular expressions arent really a primary abstraction. And even when they are, I don't see how the implementation wouldn be accessible as a lower level. They're not really a layered abstraction.
The only thing you need to watch out for is regular expression matchers that are prone to exponential blowup. But you don't need to understand anything; you can just consult a list of which ones are bad and which ones are good, and then avoid the bad ones; without any understanding of the mechanics necessary.
> You have a point, but it seems clear to me that your parent commenter was referring to more pervasive abstractions like frameworks and probably programming languages.
Probably. I was just looking for the simplest example that the maximum number of people would be familiar with.
If you're OK with the ocassional catastrophically slow regex: https://swtch.com/~rsc/regexp/regexp1.html , sure.
But you do need to understand the abstraction of strings, code points and so on, if you want to do regexes on unicode that doesn't stop at the ASCII level.
In general yes: it's not an absolute law that you need to "know one layer below". You can code in Python and never know about machine code.
But knowing the layers below sure does help making better decisions if you want e.g. to optimize this Python code. Knowing how the code will be executed, memory layouts, how computers work, access latencies of memory, disk, network, etc sure does help.
I already addressed that in my original comment. Approaches based NFAs and Brzozowski derivatives don't have these flaws; but you don't need to know anything about how they work to use them.
You just need to read one blog post that tells you to avoid regular expression matchers that use backtracking, and you are good to go. You don't even need to understand why matching via backtracking is bad.
> But you do need to understand the abstraction of strings, code points and so on, if you want to do regexes on unicode that doesn't stop at the ASCII level.
Why?
Yeah, no.
You might not be able to avoid using your standard lib's regex, or your project's chosen regex dependency - based on team/company policy. So it's not as simple as "use a regex engine that doesn't has this flaw".
Then if you want to avoid the cost, you need to know what backtracking is, to the level of understanding which kind of expressions can give you those performance issues.
>Why?
Because there are tons of factors that can affect your regex experience with unicode, normalization, different lower/upper case treatment, composite characters that don't match even though it looks like you typed the same character in your query, handling new unicode characters (ASCII 7/8 bit has been fixed for decades) and so on.
Well, yes, if someone forces you to use tools that have flaws, you need to learn about the flaws so you can work around them. Like when using a shoe as a hammer.
I'm not sure that proves anything about abstractions?
See also https://blog.codinghorror.com/the-php-singularity/
> Because there are tons of factors that can affect your regex experience with unicode, normalization, different lower/upper case treatment, composite characters that don't match even though it looks like you typed the same character in your query, handling new unicode characters (ASCII 7/8 bit has been fixed for decades) and so on.
Thanks.
Also, the poster says this line:
> Finding a dev who actually groks the gap between useEffect and useMemo, error boundaries, hook based fetching or my (un)favourite, authentication, is difficult.
But truthfully the problems those constructs solve are problems in every paradigm. If you can’t grasp the difference these things despite being a heavy user of a library, you may… want to spend some time reading the docs at some point.
The "UI as a function of state" was not just sold as "more functional/simpler", but also as a necessity to have a DOM diffing algorithm to minimize updates and be "faster".
The virtual DOM is not faster than performing direct mutations of the actual DOM, the virtual DOM is a tool that allows the normally slow approach of "blow away and rebuild the world" to be fast enough to put into use.
Prior to React, performant apps that weren't using frameworks that regenerated the entire DOM tree would simply manually mutate the DOM nodes based on what it was doing. If your app was loading a new comment, it would find the list of comment nodes and append a new one to it, same as a virtual DOM would.
The problem is that this could be error-prone in large apps—are you even sure that the comment list is still on the page? If it's not, do you need to add it to the page or is this a completely new view and you're reacting to a network request that finished after the user navigated away from the page? That's the kind of finnicky manual work that React helped simplify, but the performance was the same as an app manually mutating the DOM plus the extra virtual DOM comparisons.
https://www.quirksmode.org/dom/innerhtml.html
https://segdeha.com/experiments/innerhtml/
The thing which was slow is changing more than you need to change. When the React marketing push included performance, that’s almost always what they were comparing it to - someone would have slow code making the same updates multiple times or triggering reflows by forcing the browser to do a partial update to measure something, and then updating again.
There’s an argument that the guaranteed overhead of using React is better because it helps the average developer who doesn’t measure performance much do a better job than they might have otherwise, and that can be true for many people but it also tended to get oversimplified to “React is fast” despite widespread evidence to the contrary.
But in a comment thread of people saying the virtual DOM is not faster than equivalent manual DOM mutations you can understand why "The virtual DOM was faster than the DOM" got understood differently since it lacked that clarification.
Not really a misconception: it was explicitly pushed and advertised as such, most of the advocacy (especially from React fans) at the time React was introduced and started gaining traction was about the virtual DOM being "faster".
>React changed things so that the state of the DOM is always derived from your own app's state, which eliminates what turned out to be a pretty tedious and error-prone amount of work in complex web apps.
I dunno, I used Redux for a few years, and it was a "pretty tedious and error-prone amount of work in complex web apps" too.
Even small Redux apps can start off with a lot of indirection as soon as they extract logic into selectors. This is probably the first area where Redux becomes more complex that what you were doing before:
https://redux.js.org/usage/deriving-data-selectors
It reminds me of reading a bunch of parser combinators: it feels like you're reading code that builds something that does what you want instead of the code that just does what you want.
const makeSelectItemsByCategory = () => {
const selectItemsByCategory = createSelector(
[state => state.items, (state, category) => category],
(items, category) => items.filter(item => item.category === category)
)
return selectItemsByCategory
}I'm sure React fans who misunderstood the virtual DOM (which was explicitly advertised because it was the most popular part of React[1] vs the other parts that people were more critical of) may have said this, but I never saw the project itself advertising itself as faster than vanilla JS, only that it could be faster than competing frameworks, _especially_ ones that rebuilt the DOM unnecessarily.
> I dunno, I used Redux for a few years
Redux is a different library than React. State management across an app is a problem even for non-React applications, it's not like React _uniquely requires_ work to address state management.
I don't see why your dissatisfaction with Redux has anything to do with React making a very specific and buggy part of building web apps easier to manage in return for a performance cost and following its API.
[1]: See mention near the end of https://medium.com/@dan_abramov/youre-missing-the-point-of-r...
https://svelte.dev/blog/virtual-dom-is-pure-overhead#how-did...
Here’s @vjeux: “React is a JavaScript library for building user interfaces developed by Facebook. It has been designed from the ground up with performance in mind.”
https://calendar.perfplanet.com/2013/diff/
“Optimized for performance and memory footprint”
http://slid.es/johnlynch/reactjs
If you worked on the web a decade ago, this stuff was everywhere and because Facebook was at its peak there was this bizarre reality-denial effect where people would have an app which was slow, soaked memory like a sponge, and they’d insist that was as good as it could be because Facebook and Instagram were using the same framework. Reality intruded enough eventually that people started talking more about things like developer experience but you can still find people arguing that needing 4MB of JavaScript for a contact form is normal.
I guess you could say that not being specific was misleading but we'd have to agree to disagree on that. I _did_ work on the web a decade ago and my recollection is that it wasn't ever unclear that React's performance claims were that it was fast for a framework and not faster than equivalent manual DOM mutations.
That was a very common claim - if you search for old comments there was some very magical thinking about virtual DOMs at the time. I do agree it was worse in the fanboy circles - there’s a game of telephone where nuance is lost at every iteration so you’d sometimes have a blog post where someone said they saw a big win replacing a thicket of jQuery plugins and it’d eventually be repeated as “React is ZOMG FAST!!!!” with a few people trying in vain to suggest that replacing a bunch of organic code with something planned probably mattered more.
Anyway, my point isn’t that React is terrible but more that you really want to measure & review assumptions to make sure you’re not relying on something stale. It’s still easy to find assumptions from the IE6 era shaping what people think of as fast or slow, and especially with the massive front end framework trend it’s easy for people to have enough layers that their understanding of their application’s performance is far off. Choosing React is fine, just make the trade offs deliberately.
At the time it was. Especially compared to how apps were built at the time.
Note that even today virtual DOM libs (not the same implementation as React's) are still among the fastest: https://krausest.github.io/js-framework-benchmark/2024/table...
This makes no sense. Redux is extremely simple with a very small API. If the code using it is tedious and error-prone, that's the fault of the people who wrote that code not Redux.
E.g. "everything must be an action and have an associated reducer" is nothing to do with Redux itself.
Redux splits things up that belong together. Redux makes you write more code. Of course it's more complex.
Even it's creator advised that you probably don't need it.
This is my whole point. Redux in itself is not complex. The elaborate flows people create with it are complex.
It's not Redux's fault that you're using it when you shouldn't be.
Redux is concept overload. It's abstractions on top of abstractions on top of abstractions...
It makes simple things complex.
This has been the trend largely for last 3 to 4 years with the candidates (<5 yoe) I have interviewed. I probe them on core fundamentals of Javascript, HTML and CSS. When I get to the nuances, most of them outright call it out saying that they are React developers and do not do Javascript without realizing the fact that React is based on Javascript. And other common misconception is that they assume JSX works the same way while writing the vanilla Javascript code.
It’s useless knowledge for most people now. Like knowing assembly.
I currently work with devs who've done things like create a Map and then assign properties directly instead of using .set and .get.. I'd say that shows a pretty significant lack of fundamentals
People just assume every data structure operates like an array since it is the most commonly used without realizing the underlying object nature of the language. Like the idea of getters and setters coming from OOP paradigm is lost to fresh devs over the last 5 years using the FP paradigm as their primary means of coding in React.
So yeah some of the fundamental are missing but also most of the time this knowledge probably isn't utilized by React FP only devs in their day to day.
https://lolware.net/blog/react-xss-protection-cheat-sheet/
The feedback I got across the board was generally "what even is this code? If you it to work with react why isn't it a hook?"
I mean, it's correct that people who ask such questions should spend a year doing web dev without React probably (and maybe learn basic programming concepts). But the people who comment to you about that post seem to be self-selected for not knowing much about JS.
People who know their ropes aren't left with any questions by your article :) and probably know about everything it contains already.
Still, feedback from me: good content, especially for beginners!
I've interviewed a few people who don't know how some of the array methods work, and those are one of the most important parts of knowing how to write Javascript.
Anyone working with the language will be inevitably regularly reminded which these are.
The least mentioned is NaN followed up by... false. But I can't blame anyone for forgetting that one, as it's too obvious.
But it's just very much asking around https://javascriptwtf.com/ level stuff
Especially when you deal with unsanitized data - like from a 3rd party API - you're bound to eventually have each of those cases find their way into your if statements/expressions.
Also, this question works for other languages too, as e.g. NaN can evaluate to True (Python) or have an undefined behaviour but still evaluate to true (C, C++) - it's useful to know what is true and what is false(y) in your language of choice, especially coming from another language.
To make it worse, there is a "truthy" too.
I guess a technical question. But my eyes.
How did I do?
Personally I've never had an issue where that would matter, as BigInt is typically used mostly in isolation. Any avenue for errors appears only when types are mixed or used in boolean statements.
When all the frameworks were taking off, I was at a huge company using a 15 years legacy front-end. My background was "traditional" front-end. HTML/CSS/JS and mostly jQuery at the time.
Every time I went in for an interview, the senior devs would always start with fundamental JS stuff and then go from there. I would consistently get comments about how I was the first person they interviewed who could actually talk to basic JS stuff like closures and scope chain. They said there was a huge influx of people learning React and Angular and had no idea the difference between the two or like you said, they were based on JS.
This was back around 2014/2015 and it looks as though not much has changed since then.
After some hours I saw him walking around with that programmers walk we get when trying to figure out a particularly hard problem. So I went over to check on him.
He informed me that his code to read in the XML file and transform it with the XSLT I had given him worked perfectly in IE but in Netscape there was some sort of problem with the ActiveX control he was using.
So - I figure assuming "JSX works the same way" is the modern day version of that.
i kept my judgement to myself and just ignored his advice. hopefully he's learned html.
I was working with a senior developer who was having trouble moving something up on the the page when something else disappeared. He was using asp.net server controls, it was all he knew.
I suggested "just wrap the content you need to hide in a div and style it with display: none, your content will automatically float up"
He answered me with a sort of superior sneer: "I'm a .net web developer, I don't know what a div is, and I don't intend to learn it".
To be fair, that was a different time and MS was trying hard to make web development act like VB desktop development, but still...
The moment sticks out to me.
React does a fantastic job working with common developer principles such as Don't Repeat Yourself, and Single Source of Truth.
Their points come across as overly vague and lack any true insights into development besides initial impressions.
For a static page it doesn't make sense to use React, obviously. For a highly interactive page it, or another framework is critical to clean, manageable code.
JSX is a nice templating language. And when you use Deno or Bun you can use it directly on server-side. My server-side components have no hooks and use preact-render-to-string or `renderToString()` from `react-dom/server`.
Also there is Gatsby which is a popular content management system which also allow non-interactive statically rendered pages (as far as I remember).
Because of a poor design choice in an otherwise well designed platform (at least in the case of Deno).
If a condition in JSX gets too complex I normally extract a component-level function and call it from the JSX part of the component.
eg ``` <ul> @foreach(var item in list) { <li>@item.name</li> } </ul> ```
of course this idea goes against jsx's implementation (as it's just nested functions) and paradigm of being html in plain javascript rather than an interpreted templating language.
some of the differences i really like (like being able to assign compoents to variables, pretty sure razor doesn't have anything like that).
jsx map accepts a js function which should return a jsx element. Can I use...? If it works in js, yes.
Using Razor obviously did not stop Microsoft from building buggy web applications.
And I commend the maintainers of JSX for refusing to extend its syntax.
JSX can be learned in 15 minutes and it is a macro usually used to wrap React.createElement.
You could just as well swap your bundler plugin and use some other type of macro, e.g. sth like Mithril's m.
JSX is a very slim basic concept and I don't know a single gotcha except for the renamed attributes/props that are otherwise reserved keywords (htmlFor, className).
That you can use/see it as a templating language is just a part of its appeal.
I loathe having to use dedicated templating languages, having worked with Mustache and various PHP templating languages such as Blade and Twig.
Maybe "loathe" is a strong wors because most of the time it's easy and just works. But when it doesn't, debugging is a nightmare.
Escaping rules and questions like "what is code, what is a just an uninterpreted string" become unpredictable, and you have to learn useless baggage for each of them.
Same goes for all the JS DSLs using HTML attributes (Vue 2 "templates", which are actually not templates, etc). This is also what turns me off about htmx.
It'a great to throw together a specialized solution for one problem, but not great for libraries inventing unnecessary proprietary languages.
This is related to `React.createElement`, I think. Preact does not have this problem. For client-heavy web applications I prefer React over Preact (not all libraries work well with Preact), but server-heavy web applications are fine with Preact.
You can also complain about JSON being a mediocre data format. But I think it's minimalism and compatibility with JS made it successful.
One issue in the frontend space is that React has been the default no-questions-asked choice, but my personal vague, no-true-insight feelings are also that you need a technically very proficient team to avoid it turning into a maintenance nightmare.
Many people work for SMBs, and it feels like there's not a great golden path currently for frontend. Doing a something simpler somehow feels like a bigger risk to the people I chat with.
That's not to say React is to blame, per se, but good code is the result of good developer practices rather than some framework.
* a list of elements you can select and delete/bulk-edit is feasible with <form>
* any kind of form with input
* hide/show toggle
* tabs
* accordions
Many single page apps aren't really interactive or require minimal JS.
Currently, we're doing things in JS (like forms, pages, tabs, virtualized lists & tree views, hovers, even buttons with JS click handlers) just because our server does not render HTML.
Might as well just start with the least common denominator that everyone knows and is easily hired for
Completely painted into a corner, I gave up after about six hours of trying to get my event listeners to work with React.
It's a shame, because there's so much server side stuff I could be doing right out of the box with Next, but now I basically need to choose a completely different architecture from the one I want because I thought it would be easier to use jQuery.
In all fairness, direct DOM manipulation works a lot better than React for the original app, but now I have to keep DOM state in sync with my server, which is a whole other challenge that React solves quite nicely.
State management in React is a major source of pain and complexity and if you build you application using events then you can eliminate state entirely.
Most state management in react is used to fill out props and get the application to behave in a certain way - don't do it - too hard, drop all that.
Here is how to control your React application and make it simple and get rid of all state except useState:
const ImageComponent = () => {
const [cacheBust, setCacheBust] = useState(0);
useEffect(() => {
const eventListener = () => setCacheBust(Date.now());
window.addEventListener('customEvent', eventListener);
return () => window.removeEventListener('customEvent', eventListener);
}, []);
return (
<div>
<h2>Profile Image</h2>
<img
src={`https://example.com/profile-image.jpg?cachebust=${cacheBust}`} // Image URL with cacheBust as query param
alt="Profile"
style={{ maxWidth: '200px' }}
/>
</div>
);
};
// Component that dispatches custom event
const DispatcherComponent = () => {
const dispatchCustomEvent = () => window.dispatchEvent(new CustomEvent('customEvent'));
return (
<div>
<h2>Dispatcher Component</h2>
<button onClick={dispatchCustomEvent}>Reload Image</button>
</div>
);
};
Trust me - once you switch to using custom events you can ditch all that crazy state and crazy usage of props to drive the behaviour of your application.No libraries. No higher order components. No concepts to learn. No weird rules. No complex tracing of props and trying to work out why state updates were not triggered, or were triggered.
Redux is one of the most painful software development experiences I have had.
Just the thought of using Redux fills me with dread.
The event code above simply sends a message directly between components - that's nothing at all like Redux.
Can you describe how the above is like Redux?
https://old.reddit.com/r/javascript/comments/9vuwe3/crxcmp_s...
Link in the main comment in that thread. The library unfortunately was never released open source for reasons that are clear in that thread.
and in particular,
http://eyeandtea.com/crxoop/v2/ch01/03
for the documentation of CrxOop. It is just the OOP part of what you see here
Have you heard of Redux Toolkit?
the concept is that events subvert React's own change detection. it's definitely more direct than stacking contexts on top of each other (... or Redux, shivers)
but probably more maintainable, after all you can just search for the event name.
I don’t use redux, but I also don’t think this is the way.
What do you mean? I build systems like this all the time and they work fine, no "data races" whatever that means.
Data races are a specific example of something that happens when you don't have that observability, where the flow of events through the system produces behaviour that's dependent more on event timing than anything predictable. For example, you could have an event that triggers multiple asynchronous processes in different parts of the codebase, that in turn both access or update the same bit of state. This means that the final result of the state will be dependent on the order in which the state accesses/mutations happened. Importantly, with event buses like this, particularly ones built in a more ad-hoc way, it can be very difficult to notice when this happens without keeping the whole application (and all its possible events and responses) in your head at once.
In my experience, most of the complexity from frontend development comes from managing changing state, and one of the key problems is understanding why a given bit of state is the way that it is. I want to be able to easily trace what caused a change, where it was triggered, why it occurred, etc. But event buses can become messy because handling and dispatching a given event can happen anywhere. So even if you're sure there's no data races now, the longer the application exists and the more people work on it, the harder it becomes to ensure that data races aren't happening somewhere that you've not thought about.
That said, I agree that other state management tools that try and solve this can produce a lot of their own complexity. Redux, at least raw and with all the boilerplate, can be painful to use.
Personally, I've found signals to be one of the more convenient mechanisms for this kind of global interaction. Signals are similar to events in that they can be emitted and listened to, but they are more explicitly about the flow of data rather than arbitrary events fitting around the place. This makes it easier to hook into what's going on and see how the data is being changed. There are signals libraries for React (MobX is the classic one here), but these days I mostly just use SolidJS, which is a framework that looks a bit like React, but uses signals as its core reactive primitive.
I'm on my phone, so I can't give great code samples, but with events I'd probably write a separate class/service/tool to handle the cache busting state like this:
createCacheBust() {
// cacheBust here is a reactive getter, not just a value
// Calling `cacheBust()` in the right place will ensure that the
// effect or component will be rerun whenever
// `cacheBust` changes.
cost [cacheBust, setCacheBust] = createSignal(Date.now());
function reloadImage() {
// Update the state, trigger rerenders in any component that used `cacheBust()`
setCacheBust(Date.now());
}
return [cacheBust, reloadImage] as const;
}
export const [CACHE_BUST, reloadImage] = createCacheBust();
In simple cases like this, you can just call this "hook" globally, although in more complicated situations you might prefer using contexts to pass these values around.In components you can just import these values and call them (or pull them out of a context and call them, if that takes your fancy):
const ImageComponent = () => {
return (
<div>
<h2>Profile Image</h2>
<img
src={`https://example.com/profile-image.jpg?cachebust=${CACHE_BUST()}`} // Image URL with cacheBust as query param
alt="Profile"
style={{ maxWidth: '200px' }}
/>
</div>
);
};
const DispatcherComponent = () => {
return (
<div>
<h2>Dispatcher Component</h2>
<button onClick={reloadImage}>Reload Image</button>
</div>
);
};
You might say that this doesn't look much different to the event bus version, and that's true, but the benefit is that we've encapsulated the state somewhat. Before, emitting an event could do pretty much anything, and the state it affected was spread out over any component that chose to listen to the event. Now, the state lives in one place, and it is mediated by the exported API. If the state starts behaving unexpectedly we know immediately where we can start our journey to figure out what's going on: the createCacheBust function.This is just how things might look in SolidJS, but you can also use Preact which merges the React and signal-based worlds in a different way. But either way, I really recommend exploring signals as a way of being able to wrap the event-based logic that you're currently using in a simpler, more state-based parcel.
I'm not getting the thrust of this.
So instead of simple, easy to understand messages being sent around we are now talking abstracted functions contained in contexts to send event messages? Sounds unnecessarily complex. May as well implement Redux.
But the whole point is that "simple, easy to understand" is very context-dependent. Goto, for example, is very simple, possibly the simplest form of control flow you can imagine, and it's also easy to understand at the point that you're writing it down. It just moves control flow to where you want it to go - what could be simpler than that?
But simplicity needs at least some structure, otherwise it becomes chaos. That's the value of encapsulating both the events and the state in a single place, and then providing a limited interface to that reactive state. Yes, it's (slightly) more up-front work to write that interface out explicitly, as opposed to just putting things into events, but it has real value later on when someone else needs to read the code and understand what it's going to do.
useEffect(() => {
document.addEventListener('GLOBAL_RELOAD_CHANNEL_INFO', loadChannelInfo)
return () => document.removeEventListener('GLOBAL_RELOAD_CHANNEL_INFO', loadChannelInfo)
}, [loadChannelInfo])
useEffect(() => {
document.dispatchEvent(new CustomEvent('LOCAL_CLOSE_DIALOG_ALL'))
}, [])
useEffect(() => {
const handler = () => setReloadCoverImage(Math.random().toString())
document.addEventListener('GLOBAL_RELOAD_RELOAD_COVER_IMAGE', handler)
return () => document.removeEventListener('GLOBAL_RELOAD_RELOAD_COVER_IMAGE', handler)
}, [setReloadCoverImage])
However when programming React I try to avoid even layers of abstraction beyond what is already enough complexity.The argument against events is losing track of where they came from and what they do but honestly I found that using state to drive the application UI was vastly more complex and hard to manage and debug than event messages. It's easy to do a global search for GLOBAL_RELOAD_RELOAD_COVER_IMAGE to see what a message does than to trawl your way throw the harrowing complexity and intertwined complexity of state, props, renders and re-renders.
And when I can, I attach the events to local elements in the component rather than document, to further reduce the scope of the complexity.
IMO global events can get messy quickly and make it really hard to develop more complex apps where you have the same component in multiple branches of the DOM firing the same events.
I used to use events just like this, but once the app gets bigger it’s hard to keep track as the event keys are strings. There is no IDE support for tracking usage (functions and class properties allow jumping to and from usage).
Also MobX tracks dependencies based on reads and auto re-renders changed components. This replaces having to hook up event receivers manually to re-render.
I think there are newer mobx state management systems nowadays (Signals is the new term).
I think react is great except the concept of using a one way flow of props to drive the application via state is flawed and too complex and hard to debug and has cross cutting issues.
React provides a nice application architecture with minimal usage of props and no global state or contexts.
It is not difficult or complex at all to use pure functions and seven hooks. They are documented exceptionally well.
All the complexity author is complaining about he created himself. You can keep the browser router if you want, it can be synced with reactive state using a single side-effect and a single reducer, you don't need to replace it with react-router. You don't need to use Next.js. You don't need SSR or graphql. You can use just regular CSS if you want. This is not complexity that "comes with React", React comes with nothing like that. This is complexity you are stuffing into it.
Of course you can still write shitty code with functional components and hooks, but at least now the paradigm itself steers you towards more maintainable code
In general, hooks seem tidier, but the quirks of useEffect seem rather more surprising than the old way.
Young dev: it is way too complicated to do something as simple as a todo or hello world app. You have to configure a dozen settings, install 10,000 dependencies and fiddle with too much stuff. I'm going to create a framework that is simple, lightweight and easy to use.
Time passes, framework becomes popular blogs write about how framework X is the future. If you don't have 10 years in framework X you can't get a job. People start using it for things features get added to accommodate needs. People argue saying it's necessary it fits the demand. Framework X becomes a gigantic bloated monstrosity, development slows as useless bureaucratic leeches posing as developers create a "foundation" to "shepherd Framework X towards a bright future." At this point usually the creator leaves or is driven out.
A young developer comes along and says to himself "it is way too complicated to do something as simple as a todo or hello world app. You have to configure a dozen settings, install 10,000 dependencies and fiddle with too much stuff. I'm going to create a framework that is simple, lightweight and easy to use."
The Wheel of Development turns, and frameworks come and pass, leaving defaults that become best practices. Best practices fades to srandards, and even standards is long forgotten when the problem that gave it birth comes again.”
I have been thinking for a while about specialising in teaching how the web came to be, so people who are non-technical can understand enough to commission work, understand proposals, etc.; because I think people have no sense of what goes on under the hood.
But increasingly I think it's junior developers and web-oriented designers who need to be taught it.
(Also the developers of Hacker News: "flag" should be idempotent, surely, and not a GET request?)
While working through the idea, the most challenging aspect for me has been how to describe the value of it, even though I know what the value of it is.
I think there are parallels, like no longer knowing what is going on under the hood of your car, which has its own anxieties.
Paradoxically I think it is non-programmers who are more interested in the kind of "history lessons" of it -- like, how did we end up here, 10,000 feet view stuff. And perhaps just a small amount of that would stop people being bamboozled by copy-and-paste nonsense in proposals, quotes, project plans etc.
It strikes me as interesting to think about, that if you were to go back in time and ask someone twenty years ago if they knew much about the web, those people, who might be from diverse non-technical fields, might be able to tell you quite a lot they'd gleaned about how it actually works. Because the books on the web then taught you how it worked. Surprising people used to know about domain names and FTP servers.
But nowadays, the knowledge is much higher-level, and in a way that leads people into believing things only have complex dependencies, like React or serverless designs or Cloudflare.
It's like the web needs its own Raspberry Pi movement.
But you have to know the web fundamentals to use it well.
Also, something clicked when I read this
> But nowadays, the knowledge is much higher-level
High level is the standard metaphor for 'highly abstracted away from fundamentals' but I think 'highly nested' would be more appropriate. More abstraction levels doesn't always lift you up, and often obscures important stuff.
- Large standard library exists
- "It does too much! It's slow! It's too hard to use"
- "Here's a new library. It's 28kb and lightning fast"
- Becomes new standard library
- "... but it doesn't do this thing"
- 2 rewrites later
- Large standard library exists
It also seems quite focused. If anything is to become bloated, I would expect SvelteKit rather than Svelte, to become larger.
I also don't know how much of the bloat is to be attributed to React vs. its usual friends or their numbers, and maybe SvelteKit actually helps keeping things in order in the Svelte ecosystem.
Svelte has also been around for a while now.
(Note that I have only small experiences with Svelte, none yet with SvelteKit)
When I said "runtime", I was thinking of some support library you'd need to include next to the code of your app (which is left intact by React, and mangled to death with Svelte).
It feels like the author is confused between react (the library) and the its ecosystem. They don't need all those things in order to use React.
- Routing: Not mandatory. You can just use server side routing. You're no longer a SPA in this case, but do you need to be a SPA ?
- SSR: I actually do not understand the new obsession with SSR. If you need SEO, add a static marketing page, that might be enough for a lot of scenarios.
- CSS-in-JS: just write a plain css file and class names
- State management: useState + context API works for a lot of simple apps.
I don't even understand why "hot reloading" is even listed in the complaints. It's a nicety, not a requirement. It's not even "react".
Of course it's complicated. You made it complicated.
At this point we've been through enough front end churn, React is fine. Components, static typing, a javascript/html based templating language. Server and client side rendering. With Next.js my DX is better than anything I've used before.
Vanilla JS? Yea, no thanks. I'm not going back to square one, choose your own adventure custom framework because of your skill issue.
But I'm looking at tiny web interfaces for microcontrollers at the moment, and as an experienced Vue developer I find petite-vue and a classless CSS framework an appealing compromise for designs without a build step.
With a build step, maybe preact?
Isn't it the other way around? Those who have skill issues select React?
It's possible to write a whole load of very clever things in vanilla JS, but it's not always a good use of time to do so, and it is not a very easy way to develop things in large teams, without building up an abstraction layer with getters and setters that is not appreciably better than a minimal reactive framework.
The one-way data flow in reactive frameworks is the bit worth fighting for (and fighting over).
Though to be fair, rather than using Vanilla JS alone I did recently write my own React-looking but not React-like view engine: https://worldmaker.net/butterfloat/#/
But I’m skeptical they won’t fuck up as well. They have a reputation of breaking everything with react router.
Want to structure your code? There are 4 ways to do it. Want to fetch data? You can use route handlers, server components, or server actions. Don’t forget to choose one of the 5 ways to cache and revalidate data! Want to show a loading indicator while the data loads? There are a few ways to do it, but be careful because some ways depend of parent components being server or client side! Not to mention all of the “unstable” apis.
I appreciate that they want to make it easier to build incredibly efficient applications, but now there are so many options and so many ways to shoot yourself in the foot that I’m stuck with choice paralysis.
IMO a good framework should have one and only one obvious way to accomplish something. More advanced use cases should be hidden away in the reference documentation or left as an exercise. That’s why frameworks like Django and Rails were so successful.
I somewhat disagree that the approach is ill-suited to simple sites, server-side JSX is a strong step in the right direction. If you're using it on the server you may as well use it on the client, even for minor interactivity problems.
Wow that sentence made me want to throw my laptop.
I want you to build me a site that can be cached (think basic product shopping cart page) and then do the JS/hydration magic after the user has seen the render. Go ahead, and take your time, it's not a fun exercise in react.
As for JSX on the server side... It was a shitty idea to mix presentation and code when PHP did it and got laughed at, JS/JSX isnt special. Templating languages are LIMITED for a reason. You know code/content/presentation all being separated is a good reason to do that...
JSX is sugar for a tree, it’s not that complicated
Much of the hydration stuff is accidental completely, I would argue that all is with the advent of search engine scrapers that give the page some time to render. The goal of including associated data for the first render is essential complexity - it can save up to 200ms of latency, but there are simpler ways to do that (such as data islands, early hints, or SSE). At that point JSX is, again, nothing more than a really good templating language.
Data islands are my choice because they worked in the 90s meaning they will certainly work today. XML back then, but JSON works just as well. Of course, hydration is assumed to be the only solution for the react-size-fits-all crowd.
Meanwhile whatever server side renderer of the week framework you pick could be old news and abandoned in 5 years.
As Vue and Svelte have shown, maybe it’s time for react to include a compile step to automate some of the boilerplate/tedium and reduce avoidable bugs.
There was an open source project (https://github.com/abi/screenshot-to-code) that I borrowed the prompt from and made a custom GPT for myself where I just drag and drop the image. It’s not perfect but it’s pretty great overall!
Here are the prompts: https://github.com/abi/screenshot-to-code/blob/main/backend/...
People act as if it's all 'web development'. And then you get things like "We need to move back to server side rendering". And I think: why the hell did you think using a front-end only framework was ever good for your e-commerce website?
It boils down to this: figure out what you're actually doing, and get the best tools for that.
React is an awesome framework, but if you're building a simple blog, why the hell would you use that?
Maybe, I don’t care if it’s “overengineered” or maybe I don’t need something fast or maybe I need an abundance of talent to work on it. There are plenty of reasons why it might often be the best choice.
This is wrong. If you want to build a web app in React you don't have to use anything except state management, which you need in absolutely any stateful application anyway and which can be a literal one-line React hook.
The point about not building websites in React is valid, but...just don't do that if there's no advantage? This is about as helpful as saying you don't need to store binary blobs in Postgres. Well, no, you usually don't, but I'm still going to use Postgres for what it was actually designed to do.
i get a massive distaste on what bulky behemonth of a mess nextjs is along with the ssr etc. i fucking hate it. this bleeding edge stuff is whack.
but one thing these geeks got right is how mature the developer tooling is around react. it just all fits well along with eslint, stylelint, vite, tailwind, etc. this cutting edge stuff is good.
This is why nextJS is becoming so popular.
https://stackoverflow.com/questions/64106594/is-the-useeffec...
The situation I have in mind right now is a search field which updates a local useState value. When the user hits enter to trigger submit (or clicks submit), I want the useEffect to fire. At the same time I want to be able to clear the field and submit via another button.
I am probably not explaining it well but the missing dependency becomes a pain point in these situations. Is useRef basically what people end up using to work around it?
As for what the article above says, I do agree that the churn in the JS world in general is very exhausting. I guess it is filled with a lot of young "talent" who have endless time and energy at their disposal.
and after a few iterations it makes sense to do a jump in some non-functional metric (vite, deno/bun), or do a vertical integration (vercel), and then new tools target those platforms, and ...
if it's exhausting stop chasing the new shiny thing, and just use Angular like normal people. or HTMX :p
The idea that MVC is considered antiquated makes me wanna reach for my zimmer. Yikes.
I’d say “you younguns today” but I’m certain I was the same with the JSP/COBOL/Perl people years ago.
JavaScript frameworks are an unnecessary burden on most websites? We been on that.
Pretty much forced to build production systems in Angular in my day job. But typical process for prototyping new speculative functionality is:
$ npm create vite@latest > React Typescript
And then blindingly fast building out super hacked functionality with sub-second Write -> Compile -> Reload times (joyous vs production Angular build infra).
Then after a few demos and iteration, take it all and build out a well structured Angular app.
Signals + @if syntax in templates makes modern Angular development pretty good. And the strong separation between styles / component / template ends up creating more maintainable large code bases where a lot of engineers are contributing.
I think class based components led to really strange patterns that people thought should all be replaced with useEffect in function components.
UseEffect is sometimes necessary and then it's fine but it's a code smell too.
"React suffers churn" -> goes on to talk about a lot of things that aren't React.
"React should stay in its lane" -> React has a router to better manage lifecycle state. And it's simple and flexible and easy to work with.
"React's talent pool is diluted" -> lol
"React is not fast" -> This is true if you are comparing to e.g. htmx, but except for a bulky first load, React is just as fast as anything else.
"React is overengineered" -> React is simple. It's good because it's simple. The data flow and rendering flow are intuitive once you understand them, and once you think in React, things become so nice that working with plugins that aren't React-y becomes kind of frustrating.
React is a great framework for app dev. It has nice conventions, a simple learning curve, a good ecoystem, and good corporate support. I don't need React, but I use it because I like it.
This one in particular always seems to be pulled out by people advocating for yet another new framework. I don't do much frontend these days...for like a decade now, but as a mostly outsider who occasionally dabbles, React has been a constant for a long time now. The latest stuff in Next looks fantastic, in the real world we were never able to build anything nearly as nice as what is possible these days. There's a lot of historical revisionism and rose-colored glasses being worn these days, but the truth is that most web apps have always been garbage, and that will probably never change either.
And that's not even going into using a big component library, like Material UI, which might be its own nightmare.
This is something I've dealt with a lot personally, and I've made a good attempt to avoid unnecessary 3rd-party dependencies. But the huge churn continues in the build tooling, testing, linting, etc.
But not every site is an app.
People detest Word because not every file is a document. Perhaps you are too old to remember, some hopeless folk writing their code in a word document like it was a good thing... (it had macros and viruses even! What a fabulous program)
> React is simple.
Its not simple, though. Js is a bloated nuclear wasteland at this point, so it might not look half bad compared to the other mutated monstrosities lumbering about, but that's it.
> manage lifecycle state
As soon as you have to say that, you aren't in simple land anymore. You're in "I have 10 features and 100 states and OMG don't break production" state.
The point about "dilution" is especially salient. Call it elitism, or whatever, the popular framework/language attracts the lowest common denominator - unpopular languages don't necessarily save you from this issue, but they make it more likely that someone took time and effort to care about being a good developer, not just an employed one.
That's what he said. He said it's good for app dev. Sites that aren't an app (or web app, or SPA, or whatever we call those things these days) should not use react as it makes no sense as a choice for that case
This is something I see people criticize react a lot and it makes no sense to me; "React isn't good at a static site/fast HTML page/non-stateful and complex app!!" It's not supposed to be! It's not for that. It's not a criticism of the framework. I'd love to read a criticism of the framework for what the framework is used for: complex stateful web applications.
React rendering can get very very slow. A classical example are inputs that update very slowly when you type something. "Best practices" lead us many times to this when we round-trip the whole state from input change event, to global store object, immutable changes and back to the input. You can fight it with React.memo and by just mutating the state in-place.
Recently, I found valtio helpful as it allows to hook React components to rendering for parts of the global state.
Also all this useEffect(), useLayoutEffect(), and when it's not enough useEffectEvent() [1] and useEvent().
[1] https://react.dev/reference/react/experimental_useEffectEven...
We are using this approach in one of our projects at work and it’s been working great.
Technology builds on top of itself. Might as well use the things that make you more productive. The DHH ideology of anti-modernism makes some sense in some cases, but most of the time it doesn't hold up. Thank god I can deploy my static site React app to S3 with some GitHub actions and don't have to FTP a whole site into some Linux server I pay $5/month for.
The alternative to the „static site React app“ you‘re hosting on S3 would obviously be static HTML.
I actually enjoy doing this, it's also easy to automate with github actions too
Interactive sites: Django with server-side template rendering, very minimal Javascript, CSS via tailwind, bulma, or bootstrap. Buy themes if needed.
Payment, billing: send users to something like typeform+stripe, avoid building custom payment processing, order management, etc.
Web applications: things that need complex interaction in the browser I'd choose react.
When React started to gain traction, everybody scoffed at them. JSX was weird, uni-directional data flow was weird, ES6 classes were weird, too many building steps were weird. But it quickly became clear that this was the way forward. Traditional MVC approaches quickly failed once you got out of the example code and into more complex use cases. Which brings me to my point: React was better IF-AND-ONLY-IF your webapp needed to do more than basic forms.
React was never meant for consumer websites. It was never meant to be the default tool for anything on the web. If you wrote a web application, something complex, something with forms, planboards, custom UI, then yeah, it would be a sensible choice. It was meant to solve the problem that doing two-way binding of data is incredibly difficult if you have anything more than some standard form components.
The reality of the situation is that innovation in frontend websites (as opposed to webapps) has mostly been standing still, as everybody just switched to using React. CSS has gotten much better, but doing something like a form rendered with PHP + some validation with JS is still a pretty painful experience. HTMX is probably the best attempt I've seen, along with Elixir and the Phoenix LiveViews.
Most of the effort seems to go into writing a bunch of libraries for React to solve the complexities of having to deal with a complex set of tools for writing complex webapplications. These abstractions tend to either be complex themselves, or are leaky.
I realize my next sentence might as well be 'get off my lawn', but I really hope that devs stop focussing on writing the next state management framework, or routing library, or even rewriting existing things, and just try something to actually move dev forward. Open source a kit of sensible standard components including styling for webapps. Write a simple JS tool for some form validation. Show your barebones NodeJS app rendering HTML and processing forms in an PHP-esque way, give it a logo and a fancy name, chuck it up on GitHub. Don't try and combat complexity with more complexity. We have all the tools we need to write complex webapps. Please make simple websites easier, so people can stop complaining about the complexity of the complex tools meant for complex use cases that they don't need for their simple case.
I work on a badly written react application. I sometimes sift through our microservices written in go, ruby, and Java. They're badly written too. This is not an indictment of those languages or whatever framework or technology was used in those services. Business requirements change, engineers change, and refactoring doesn't give management anything to brag about so nobody gets time to clean up the mess.
Complaining about the "churn" is even more asinine. React continues to support more usecases. New frameworks and technologies are competing and challenging one another to improve. God forbid we might have to learn something new.
Also, I do think packages like those from tanstack have made it easier to implement react well. From what I can tell, most people's bad experiences with react come from applications which incorrectly use redux or similar global state as a cache for data from the server. The new Redux Toolkit Query and similar Tanstack Query approaches to handling server state are much more manageable, and in conjunction with appropriately using URLSearchParams you can often get away with no/minimal global state.
In other words, React is not the problem.
That's very confusing. But so is the entire article.
While I have your attention, as a relative newbie to web dev (with limited time and focus), is Next.js my way to go?
However, if you just want a static site, Next.js is great.
You could also write native astro components which are very close to vanilla html css with added benifit of making reusable components and scoped css. And you can also use svelte or vue components.
Honestly, you can use Astro and then still use React if you want. Doing so would be similar to next.js in some ways, though you need to hook up an adapter if you want server-side rendering
I believe Docker works because you're doing "npm run start" and containerizing Next.js, essentially proxying the server to then serve to the client. Basically running it on localhost. For example, you can run Next.js on EC2 if you want, but you have to proxy the connection to allow the client to connect to it.
Again, I'm not an expert as to why exactly it doesn't work - I just know that it doesn't work the same way a simple node app works, which therefore adds a ton of steps involved that don't make it worth it to me.
We moved a project at work and it’s been night and day for us. Not going back.
Obviously "it depends (TM)" on a bunch of things but for most of those things, Next.js is a safe bet, sure.
It's a (the?) leader in the React framework space and the ecosystem reflects that (e.g. most problems or decisions a newbie would run into is likely to have a trove of docs/blogs/tutorials/ect. available to get past them quickly, plenty of options for hosting, marketable as a skill if that's what you're into, fine DevEx all things considered, it'll likely be around for quite some time even if vercel shuts down tomorrow.) The same is true for React.
I'd personally go with Remix though :)
Downside is that there are many jobs yet.
Svelte is certainly easy to pick up, compared to anything React oriented like Next IMO. That said, the issue I had with most of these frameworks were integrating other libraries into them and quite a few of them seemed to not match with whatever version either the framework was using, or the libraries themselves were outdated.
Then again, I'm a noob at this so it most likely could have been my lack of knowledge.
React is just another example of how rot takes over what is good. And people confuse loud with popular, popular with good, easy with simple, and tedious with merit.
I know a best mind, he made htmx.
The discussion progressed as you'd imagine.
"NPM ecosystem is the biggest developer ecosystem in the world", he replied.
It's hundreds, thousands of silly dependencies taking countless disk space, and a waste of time "minimizing" what should have never been there in the first place.
I avoid Node.js like the plague. I feel nauseous just thinking about that.
...Why is there always a new way of doing things? ...Why am I learning the same thing but in a different way? ...Why was the "old" way inferior? ...Why change at all? Browsers don't move THAT quickly.
Ask why?
Welcome to the rest of your software engineering career.