Kind of annoyed at React
blog.cassidoo.co
blog.cassidoo.co
I've worked on 4 large react code bases and they always devolve into these blobs of non-deterministic async state with unpredictable performance.
I actually like JSX and the component model so I just use solid-js which is everything I like about react but with effortless performance and you can actually get away with never using effects so your code can actually be deterministic.
Exact same experience here. I've been banging this drum for years. When hooks came around I thought they might make it better, but alas, we are still in a downwards spiral. Building web apps is 10x more complicated today than it was ten years ago, with nothing to show for it.
I'm happy to see some known voices in the community realizing this, but also sad that this is how things work now. The rise and fall of React will have been both a product of social media / developer celebrities.
You can’t have an easy solution when you have tons of interaction and state.
My comparison is always with Svelte / Vue, and also what we had in previous eras (Backbone, Knockout, etc). HTMx is picking up steam too. We used to push out interactive UI in days/weeks, and mind you, in the past websites did not look all the same. There were no component libraries to start from. Today it seems most React projects are planned in months/quarters despite being built atop a mountain of third-party code, all meant to 'speed things up'.
What we do today is not faster at all, too much time is wasted on tooling and issues that arise from React's architecture (hooks, ssr, data loading, error handling, async issues, black-box performance issues, dependency hell).
It's been neither of those things and I'm actually beginning to regret making that choice.
Desktop software was never this fragile.
I feel like "X new library/framework's code is a mess" is the new "People don't want to work anymore" trope (that older workers have been saying for over 100 years).
This could be said of any team using any technology. If the team is better at using it, and they are provided more time to use it properly, then they'll make a better product. That's not unique to React.
React sucks because its scope creep makes it difficult to maintain, and there's a pretty low ceiling for the end user's experience. Yes, better teams can make better products with React than worse teams, but that doesn't mean that either end product is any good.
If Facebook.com cannot get it right, who actually can?
"No True Scotsman" is also a trope going on for > 100 years, yet you are appealing to it.
React, however just clicked. f(state) = UI just makes sense
Throw in SSR and component memoization and you really have no idea what caused a UI change to occur.
As much as I like the React team and appreciate their willingness to try things (and hooks have grown on me a little), they are human, and I think some of the decisions and direction they've taken things is a mistake.
I was part of the team who deliberated on the decision to use React over Vue in WordPress, and one of the reasons for my personal preference towards React was that it embraced JS rather than inventing a whole bunch of new things - yes, there was the funky syntax of JSX, but aside from that all the statements were regular JS, and it was much easier to conceptually understand than learning a new language. Hooks started taking us away from that, with weird functions that magically encapsulate state, and things like suspense and server components have strayed further from the light.
Making things like Next the official pathway to getting started with React is great and all for people building Node SPAs, but there's a whole wide world of software outside of that bubble, and I hope the React team peers out a little more often.
Like the original article, I’m just kind of annoyed at React about this. There’s probably great reasons to change (albeit, I don’t really think even that comment communicates them well), but it’s annoying.
Similar to how Tanstack Query doesn't even mention MobX as a state management library. It's crazy how many people use MobX for beefy apps(even Microsoft use it) but how little attention it gets.
I quickly evaluated zustand and liked the hook based API much better than mobX. Feels even more lightweight than mobX.
It works with Vue, React, Solid, and nothing. So it's there for me and allows for multi-view-library pages backed by the same stores.. Niche, but clutch for certain extensible apps.
Totally agree with your point about node backends. So much of the world doesn't and is not going to have their backend entirely or partially on node. But to the authors point, Vercel is Reacts daddy now and daddy needs to sell some hosting(for a new pair of shoes).
That's already the case, thanks to hooks. Hooks are weird, and should not be taught to junior programmers because it will confuse them for the rest of their careers. Hooks are weird because it doesn't align with functional programming paradigm or with OOP paradigm... it is a new paradigm and it is like nothing else.
More on that: https://medium.com/codex/can-we-all-just-admit-react-hooks-w...
Fire? The wheel? Penicillin?
Maybe it's just because I'm getting older, but I'm increasingly annoyed when people use these sorts of over-the-top hyperboles.
Off course it's a violation of some theoretical principals. So what?
What I don't get: people complain about not being able to handle all the useEffects, but they probably shouldn't be there in the first place. In my experience most ambiguous use effects can be easily removed. They are rarely needed for anything but library code or interaction with browser APIs.
I think this is the crux of the issue. One's view of hooks depends a lot on the sorts of codebases they've worked in. Maybe the sun has always shone on you, and you've only ever worked in projects where hooks have been used sparingly and with great consideration.
You're very fortunate if so. I've seen some truly horrific hooks-enabled messes that have had to be outright abandoned because they became too complicated for anyone to understand or debug.
People are just way too much thinking imperatively, like decades of OOP thought them (and many of their educators). Most naive useEffects are just masked derived state.
But hooks aren't pure functions. They aren't referentially transparent and have an implicit dependency on call order. Likewise, React components aren't "functional" the second you use any of these APIs which subscribe to effects, state, context, whatever coming from elsewhere. React is simply not a "pure functional" enterprise and it's strange to represent it as simply a "violation of some theoretical principles." Those principles are the entire basis of what constitutes functional programming, which is why the original parent described this as not-functional not-oo.
When I read complaints about hooks I'm either missing something fundamental about why they're bad, or the people complaining are missing it.
Curious what specifically about them is difficult or hard to understand?
Cause you're inevitably gonna want to track loading state, error state, refetch on error, revalidate etc etc.
swr or tanstack-query are great and remove the need for useEffects for API requests. For sure they come with their own overhead, but there isn't getting away from the complexity of handling API requests and all the possible paths that can happen.
For accessing browser apis useEffects are the way to go, but those are usually extremely easy to understand in my experience. Or just use a library that provides the needed functionality.
> useSyncExternalStore is intended to be used by libraries, not application code.
https://react.dev/blog/2022/03/29/react-v18#usesyncexternals...
No. Wtf? Don't do that. Never do that. Effects are for legacy DOM manipulation (and ad-hoc use of browser apis). Pretty much nothing else. Who tampers with states and data in useEffect is hellbent on creating spaghetti.
Can't really fault developers for falling into this useEffect trap when even the official docs show that data fetching is indeed handled via useEffect[1], while at the same trying to yell at the reader to "NOT TRY THIS AT HOME" and just go use a framework because it's such a complex problem... which naturally just creates more questions than answers for the poor developer trying to understand how it all works.
[1] https://react.dev/learn/you-might-not-need-an-effect#fetchin...
There are so many things about syncing data between the client and the server that this section of the docs should just say "Don't", use Apollo or Redux or whetever. React is UI library, for data you need data library or at least general state handling library. Quick and dirty will bite you tenfold.
The companies I've worked with had hundreds of engineers contributing to the react codebases and people are just trying to crank out features by the deadline. I'd rather just work with tools that don't require the usage of such obvious footguns. You can code solid-js and svelte and never use effects (even though they do offer them unfortunately).
This is the how the majority of tech companies operate.
> but I know better than to single out the tool for every judgment on design.
I disagree, most react developers are not even aware of this massive foot gun. I do blame tools for problems that are completely avoided by other tools, we can just consider this a difference in philosophy but I prefer to use tools that make as many types of mistakes impossible as they can.
Hooks enable complex patterns too easily and I think this causes a lot of breakdown in what would otherwise be simple applications.
its overuse makes it evident that hooks (or React in general) is poorly understood
Hooks fundamentally altered the contract about the API that React provided, and suddenly magic was popping up everywhere. Thankfully suspense never really caught on, because that was even more magical.
I do quite like the developer ergonomics of hooks, but it does make me wonder about whether there was a world in which we could have had both the ergonomics _and_ something less magical.
(Aside: that Medium article is available to members only.)
Hooks on the other hand are functions that you call, which implicitly rely on a magic global state and context, and you cannot use them like other JS functions. You can't conditionally call them or change the order of them, because they contain a unique ID based on call order, which is Spooky (and is why React has to build its own ESLint rules to make sure you don't mess it up!).
Don't get me wrong - I do think the ergonomics of hooks are a lot better, but I think at least part of that is due to it being a newer iteration of the API.
You don't put imports in if-s or for-s. It's as simple as that.
There’s not necessarily bad reasons for this, but the cognitive overhead of this is relatively high compared to existing language functionality.
They use subset of function syntax to provide unique functionality. That's all.
JS was full of such things already. Functions that are hooks (in traditional sense of the word) into some platform provided functionality. setTimeout(), fetch api, promise chains, jquery. You could say that all of those are just functions but you still need to learn what each does separately to get behavior you want. JS is not Lisp where a function means just one thing used always the same way with same restrictions. JS uses functions to construct idioms that introduce functionalities foreign to the core language. React hooks are just one such idiom. You may still argue that introducing yet another idiom is unnecessary burden. I personally like them very much. Component classes were imho very bad conceptual fit for react with a lot of intricate lifecycle methods and special fields. Hooks allow to simplify the core of it to just render that just runs every time it's necessary into which you are bringing in additional functionalities as needed.
Lisp uses dynamic binding for that.
(defun do-something ()
(funcall *something-to-call*))
(let ((*something-to-call* 'turn-the-light-on))
(do-something))
The behavior depends on the dynamic binding, which provides the context...What's sad is that the class-based component system did have those necessary features, it also had a nice distinction between components and their lifecycle and the rest of your code. Now with hooks, everything is React lifecycle code, unless you're really smart about your API boundaries, and in my experience no one makes good re-usable hooks that are nicely isolated from business logic.
I'd call that a pretty good definition of a "design pattern."
In this case, it's also magic framework code.
Today, I don't even feel like logging into Facebook, because a fucking dropdown menu for a post (which barely has 4-5 options) is a Component that is loaded via AJAX. This is not even an overstatement.
I miss the simplicity of the web.
Maybe I'm just in adt and marketing ech too much but it's almost like I can't be too fast on clicking thing otherwise things get fucked up and lose their states.
Also, one time, they managed to deploy code that broke form submissions under Firefox but not Chrome. I would be more understanding if it dealt with some cutting-edge features of HTML, but these are HTML forms. Mosaic had support for them in 1993.
React components should be simple stream transformers, nothing more. Accept props as input, produce deterministic HTML as output. All that other crap? Calling the API, massaging the data, business logic? That belongs somewhere else, outside of your component.
And nobody is forcing react developers to mix too many responsibilities into one component.
To be clear: I don't mind React per se. Some of the best UI codebases I've worked in were React -- they just had a very strict separation of concerns and one-directional data flow via something like MobX or Redux. All the business logic was kept separate from the UI. But that's not fashionable these days.
What kind of frontend stack would you recommend that enforces keeping some meaningful separation of concern, without limiting productivity?
Without limiting productivity, I have no idea. I think you have to limit productivity along some axis or other, otherwise your codebase just turns to quicksand.
Who cares?!? Imagine trying to justify your decision to choose a framework to a manager by talking about their diverse leadership.
Funny thing is they say it’s for the DX to become more like PHP. But the PHP I remember was practical.
- It is not listed as an option for starting a new project in the React docs[0].
- The last release was April 12, 2022.
- The last time I created a new project with CRA, it printed a console log that claimed CRA was deprecated. However, the message seemed to originate from a dependency rather than CRA itself.
All this was enough to convince me to move to Next.js for future projects; though I find Next.js overcomplicated and full of things I will never use.
Lit-html for near zero-cost dom updates.
Been doing it for years, and struggle to understand why anyone would want to put up with the complexity of react.
They are nice in theory, but I don't see that many benefits over simple SSR, or the more traditional concept of server generated HTML with interactive islands.
Next.js applications often feel way less responsive than SPAs with proper pre-rendering on first load.
But I'm really doubting if Next.js is actually solving this problem. They are heavily caching everyting, so it might bring big benefits with slow and weird backend systems.
I think those people would be better served by frameworks that hold fine grained reactivity as a virtue. If you have appetite for spaghetti at least use real pasta instead of trying to roll steak into thin stripes to tangle it.
React should start by a simple initialization: -> Setup React -> CSS library -> State management
And then, other packages or libraries can be considered to be added whenever the current needs of the application exceeds what the bare minimum setup has provided.
While in the end the set of packages and configurations performed may tantamount to what a framework already provides easily, the cognitive load starts on a piece that is well understood and grows alongside the evolution of the software product being delivered.
- The functional programming model (State => UI) allows building very complicated interfaces in a very simple way, by defining dependencies with useEffect() and other hooks. It can take years to master it, but when you develop complex apps where all kinds of state needs to update when some other state changes, you really appreciate how simple it is to do with React.
- React is very backward compatible and allows you to migrate codebases to newer React features slowly over the years, while already using those new features in other parts of the code. (I still have some class-based components here and there.)
- There is a huge ecosystem of existing React components and tools you can use in your applications. They make it a very productive environment to get stuff done quickly. Frameworks like Next.js make it a breeze to develop and deploy static apps e.g. to S3.
- You can apply your existing React skills to React Native when you need native apps.
Please don't. useEffect() is for pluging 3rd party DOM components into react. Not for doing anything else. Definitely not for any state manipulation or dependencies.
- useEffect is a React Hook that lets you synchronize a component with an external system.
- Connecting to an external system
- Wrapping Effects in custom Hooks
- Controlling a non-React widget
- Fetching data with Effects
- Specifying reactive dependencies
- Updating state based on previous state from an Effect
- Removing unnecessary object dependencies
- Removing unnecessary function dependencies
- Reading the latest props and state from an Effect
- Displaying different content on the server and the client
https://react.dev/reference/react/useEffect#specifying-react...
What you should have gotten from this list of every possible use (and misuse) of useEffect is that it's for interaction with external things. And if you are doing a lot of interafacing with external stuff you should use a dedicated service for it, not pollute your code with ad-hoc bits of interaction, each wrapped in their own bespoke useEffect().
And the linked section talks about specifying dependencies of the code block inside useEffect()
You don't define dependencies WITH useEffect. You define dependencies OF useEffect. And you don't have much choice in the matter. Any local variable (also parameter) of render function needs to be a dependency of useEffect code. As this section states.
Here are some common misuses: https://react.dev/learn/you-might-not-need-an-effect
React is UI library. Just because it can do a lot doesn't mean it should do everything. Especially in larger apps.
Or you could write your router in the form of a service that lives directly in the history api event handlers and communicates directly though react state setters of some top-level component. Not a single useEffect needed.
Besides, router doesn't usually send you anything. It just sets props on your components according to url.
You don't need useEffect() to react to anything. React itself reacts to state and props change.
You'll do yourself a favor if you ban yourself from using state setters inside useEffect(). Try it.
One benefit is performance. useEffect() causes cascading updates when it alters state.
The other is that it's way harder for your code to turn into spaghetti if you don't sidestep the whole concept of React where raw events trigger global state updates which causes react to do automatic re-render of UI which provides user with means of generating events. React should have one large loop, not multitude of small ad-hoc ones built on the side with useEffect().
"Don't load data in useEffect!"
Okay, but [this and that and this] so how should you actually do this?
"Oh, use useEffect duh! We meant.. Don't, like, use it too much."
"And React function components should always be pure!"
Wait, aren't the hooks storing and mixing states into the function in a way that's almost creating a sorta sudo object? How is that pure?
"No, we mean 'they are pure!' when we want to be dismissive. Of course they are not really "pure".."
Edit: The one weird trick they don't want you to know and will have all the React CRUD kiddies screeching; Use useMemo to kick off work early ;)
We have been deeply mislead these past couple years. React ecosystem should have been working on better faster front end systems that integrate data better. Redux should just have been a start. Instead, managing data has gotten more complex and worse.
In general, for us: the Vite + Preact team feels just right.
Anyone recommend a website framework that might allow me to completely avoid html/css/javascript?
React is darn good. Don’t mess with it and go into enshittificaion.