I'm still a React guy. I've also worked with Angular and Vue and toyed with Svelte.
People tend to compare these frameworks on things that don't matter - often it's performance. We used to compare React performance to AngularJs performance too, which was meaningless.
VDom is nice. Reactivity in signals is nice. Limiting rerenders is nice. But I choose frameworks because of developer ergonomics.
The killer feature for React was - 1. JSX - typing and auto-complete for components, colocation. 2. No direct dom access. (Good bye $element)
Most frameworks outside react still use templates. Even when they support JSX like syntax (aka vue 2.0) the default are templates. Templates are a no go for me. I use them for blogs or static websites, but applications are easier to make and maintain with actual javascript.
Luckily none of the other frameworks, even Angular, have rampant direct dom access anymore.
Hooks aren't a problem in general. It's just the useEffect hook. Unfortunately that's a big problem. That hook should never have existed. And it was clear from the start it'll be a pain from the limitations around it. It requires a mental model detached from everything people are used to and from other things around it.
When using React I usually just use MobX and everything just works.
React is very sluggish when updating many elements at once, for not very large values of "many". With some regularity, I've debugged React+MobX jank issues where a bigger update, such as switching from one panel to another, takes upwards of 200ms on a mid- or low-range machine.
None of this is perceptible on our beefy dev boxes, which is why I think people disregard it, and why the modern webapp experience is so miserable for the average person.
Performance of frameworks is often irrelevant for products/applications.
1. Performance is very very rarely a contributor to a product success. Users prefer more features over more performant app all the time (both directly when asked and indirectly by what products they choose).
2. Rendering/client computation speed is rarely a contributor to real and perceived performance. It's almost always the async calls - how many you have, and how long they take. It's almost always a waste of effort to try and make your framework render at half the time when 99% of your lag is a database call.
3. Framework performance is rarely a contributor to the speed of your rendering. It's most often a problem with how you structured your app. You can structure your app poorly in any framework. (I would hazard a guess that in your panel switch example a differently structured React+MobX solution would not have the problem you described)
4. There are only very few scenarios where the rendering speed between frameworks makes a perceptible difference (usually when talking about large tables or similar scenarios), in all other cases it's a difference of a few milliseconds.
> Performance is very very rarely a contributor to a product success. Users prefer more features over more performant app all the time (both directly when asked and indirectly by what products they choose).
I close sites allthetime when they fail to work quickly. I have aborted orders on sites midway through when the interaction became sluggish enough that I wasn't confident in the value of the product anymore.
This statement reminds me of those Gordon Ramsay shows where a restaurant owner says "the customers like my food!" when it's obviously subpar. The fact is that the customers that didn't like the food politely go away and don't come back.
Your other points get more directly at framework performance versus other performance concerns. I have fewer opinions about those.
Indeed, and I regularly watch other people give up on websites when they perform poorly.
And this isn’t just about 100 ms here or there. The frequency with which clicking a button takes seconds to have any observable effect is quite high. Coupled with modern UI trends where interactive elements aren’t clearly distinguished, sometimes users can’t tell a laggy button from a not-a-button.
I suspect a massive UX study bias here. Are people looking at telemetry to try to see whether users who completed some flow are happy? Those users (a) completed the flow, so they didn’t give up and (b) are likely enriched in those users who would use your site no matter what. The marginal users of poorly-functioning websites aren’t in the data set!
And I never click on Ads. Yet they work and drive a lot of traffic and money to sites. (Even after all the fraud)
Products almost never compete on performance, and the biggest, most popular ones are almost always the slower ones.
Regardless of your anecdotal evidence, there is a reason why this sentiment is prevalent in the industry - because PMs and devs who thought otherwise were quickly outcompeted by those that moved faster and released more features.
Why do you think there some much time and effort going into improving performance of computing in general. Facebook Lite, android go, GPU's, cpu improvements, 5g, etc.
The important caveat is that once it's fast enough the gains are marginal.
Performance is obviously relevant in the margin. A performance improvement in your site might decrease dropoff or churn by something like 1-5%, which is a good number, and it will compound.
But if you are still at the stage in product development where adding features will increase your addressable market by tens or hundreds of percents (which doing things like ‘supporting multiple European languages’ or ‘adding google login’ can do) then those performance gains are not where engineering investment needs to go.
Arguing features vs performance is really about which features are more important. Performance is just another feature.
I use Vim and I use VSCode. There is little debate about which has better performance and which has more features. It's also easy to see which has more users.
Marginal performance (i.e. 100 ms to 10 s per action, not multiple minute delays) is somewhat important to end users and matters only if they can switch easily. End users typically have little to no say in choosing the business software, especially after it's already bought.
Performance is usually a lower order concern than an app doing what you want. You can bail on a slow app because you're impatient all day long, but if it's the only way to do the thing you want to do, I 100% guarantee you're going to suck it up and use the app.
React/competitor performance that people use to compare frameworks is about rendering performance. E.g. React takes 100ms longer to rerender 10,000 elements (random numbers for the example). In these situations the actual real world difference will be negligible.
Site performance is much more API based, and that’s the same regardless of frontend. React has more library solutions to optimize the UX though, as it’s the most mature and popular.
Exactly. And those API calls are going out over the network. The caller has to serialize the request into text, the API implementation has to deserialize the text into values that can be passed to a local implementation function and then the API implementation has to take the result and serialize it into the return. Finally the caller has to process the result.
That's the simple case. Things get even more involved when you start using HTTPS to secure the data in transit on the channel and using OAuth to secure the access to the API. What appears to be a simple API call turns into a lot of back-and-forths with multiple servers - with all the network latency that entails. Then developers complain their website is slow. Gee, I wonder why!
Not exactly true about "performance is more API based".
Everything adds up. 400ms here, 700 there. Websites can be slow even before api calls are triggered or on the middle of them, or while the results from api responses are presented.
Rendering performance can definitely add up, but rarely do React websites render so many elements that you get to 700ms. Once you do, you can nearly always fix that with an performance optimizations iteration. I reckon that issue is just as likely in all frameworks, and less likely to be about React using 0.2ms (or something like that) longer per element to render before optimizations.
People are tempted to use react in the animation frame render loop, and these comparisons often seem to assume that that is the level of performance we need to be targeting - enough to hold 60 fps. But react’s not a good fit there. Other animation techniques are better for a vast number of reasons.
Performance obviously matters, but only to the extent that everyone has a threshold for how much sluggishness they're willing to tolerate. For the majority of use cases, React is performant enough that devs don't have to go out of their way to optimize anything.
> Performance is very very rarely a contributor to a product success. Users prefer more features over more performant app all the time (both directly when asked and indirectly by what products they choose).
Yet this is what all the JS people were saying in 2014 - 2015 when everything started to become SPA. They argued this is what the users want. That's been used to justify all this stuff for a very long time if you're on Twitter. When it gets traction within Twitter it leaks into orgs. It's the same argument that's used now for all the SSG,SSR,hydration,edge and whatever other buzzword.
The internet is miserable because of all these React sites. I know first hand because my wife has a Chromebook. Yet developers won't listen because they think 6x cpu slow down is good enough to test with on their $4000 Mac book pro.
If users really don't care that much about performance then why aren't we just rendering html and sending new html on every interaction. That's much easier to do, performs pretty well from a CPU/Memory standpoint.
We've taken on a lot of complexity over the years in defense of the users. The argument I go back to is what is "good enough" and the developers/product/design I've worked with don't know what this word means.
Although I agree with the sentiment of your post, #1 is blatantly wrong.
Most of my successful work has been specifically outperforming the competition in a way that makes users choose our product. Performance is an orthogonal feature that improves all other features, and even changes what your clients can do with your system, as in making new workflows viable.
That’s highly dependent on the type of product / customers you have. If you’re running an online shop selling ice cream, going from 100ms to 2ms list sorting speed isn’t gonna get you more sales. I’d argue most online products are ice cream shops to some degree.
That said, having a performant website is nice, both for developer experience and for users.
I have to say I pick solid because it's so damn fast (okok, and because it has an API which is React-like but without the crap doesn't make sense or an extra custom runtime just because)
Try to do an a/b test and see the results for yourself. Also remember that those 100ms can in some scenarios turn into 300ms if you are not running on state of the art hardware, like most developers does.
1. The obsession with measurable "product success" is part of the problem. Nobody will tell you they prefer your app because of performance, because it's not a perceptible thing your average user will notice. Features are much more important, true. You shouldn't care about performance at all for a prototype, true. But when you have an established product, not caring about the speed at all is a mistake IMO. This also has second-order effects for battery life, for example.
2. True, it depends on the type of app. For anything that is a type of "editor" - website builder, word processor-like thing, kanban board - you operate on a data model that you save in the background. Async calls are fairly unimportant for the overall feel there.
3. To me it's hard to untangle. The reigning paradigm is declarative UI, for great reason. It's so much saner than any manual updates. But this encourages a design where you don't think about what DOM updates will really happen after an action, and this is where the problem lies. A big part of it is also the DOM model and layout. In the extreme, you have a declarative UI library like ImGui which doesn't have any VDOM, it just rerenders every frame, and it's insane how quick it does it. I haven't been able to bring it to its knees, it just maintains 60FPS constantly, with a lot of frame time to spare.
4. It's not hard for me to believe this. I didn't say other frameworks are better. Could be that the whole DOM diff approach is the culprit, or the slowness of DOM updates and relayouts.
> Framework performance is rarely a contributor to the speed of your rendering. It's most often a problem with how you structured your app. You can structure your app poorly in any framework.
This is absolutely true!
I would say that some frameworks make it easier to make mistakes. For example, Angular can be highly performant...but the automatic change detection kills performance. But wait, you can fix that! Just make your components use OnPush Change detection!
...which is not...the default? Why? In any Corporate app that displays complex UIs you absolutely need to be using it everywhere. but yet.
Personally, I think it is to make it easier for beginners who don't understand why their observables are not showing content on the page but it is still annoying to set it in every component or hunt it down. This is a small part of why we turned to using nx and generators with configurations that add it by default.
> Performance is very very rarely a contributor to a product success
You might as well say, having users is very very rarely a contributor to a product success. We're over two+ decades into the 21st Century and we're still pushing a 20th Century mindset?
> Having users is a path to monetisation but having a high performant app no one uses is not.
These two things are also not the same. You start with "having users" and assume they're willing to pay and will stick around. You compare that to "having a high performance app no one uses" - explicitly limiting the scenario with an unrelated caveat that no one uses it.
A better comparison would look only at having users vs. a high performance app, which has too little information, or having users that aren't willing to pay vs. a high performance app that no one uses, which leave you in the same boat.
People pretty regularly say they buy iPhones because of the very smooth UI (performance), that they buy an ARM Mac because it's so much faster, etc. Google won partly because it was so fast.
So people do explicitly justify usage decisions with performance, all the time. Agreed that overall features win out but it's often the case that multiple products end up with broadly comparable sets of features and struggle to gain a persistent advantage there. Once you reach that point, perf can be a competitive advantage.
Not sure this is true. The following post has issues but I do find sense its argument that the result of what you are saying has been accelerated shrinkage of the mobile web as businesses increasingly use apps instead.
> issues where a bigger update, such as switching from one panel to another, takes upwards of 200ms on a mid- or low-range machine.
We have a React+Redux search page where clicking checkboxes takes about that long to update the checkbox, on our good developer machines.
I won't rule out we did something wrong (this page was pretty early in our React understanding), but we've also not managed to fix it due to how much is on that page.
I once worked for a pretty big and popular ticket selling company where you couldn’t type your credit card number too fast because it would miss numbers.
It was all redux’s magic and simplicity was making almost the entire thing rerender on every keystroke. Of course it was the developers fault, but it’s so easy to end in that situation that I blame the tools because to me when you shoot yourself in the foot that many times you start to ask yourself if what you have is a footgun.
I have a beefy machine and fast internet. Yet, JIRA is annoyingly slow. Half the time, pages on my bank’s website take forever to load, or don’t load at all.
I don’t have any numbers, just some anecdotal experience like the above.
It is not just speed. The UI of many sites suck too. Amazon, GoDaddy, for example.
Then there are ads. We don’t see ads in between content anymore. It is content within ads these days.
I am thankful that we can do so much online these days. But the experience could be better
No really. It is a B2B company that sells an idea to large orgs. "Know what is happening for everything and where you will be in a month.
It is not "Enable your workers to work more efficiently".
Jira simply doesn't really care about the average dev or such. In fact, most orgs use such a wildly configured version that it is pretty absurd.
Let me give you an example: Most companies have a workflow: To Do > In Progress > Testing > Done.
Foundationally, Testing and In Progress are tasks done by different operators.
Jira doesn't, out of the box, conceptualize who tested a ticket and who developed it. It is all one field. You don't have seperate pointing for testing and development so you can't track QA capacity (Which is helpful to a team but not to overall planning as it just causes rushed QA).
You don't have historical views of prior sprints "What was that Ticket I worked on last sprint?" (because that means nothing for forward velocity other than the final number)
I could go on..but it all leads back to an absurd UI focused purely on projects and velocity above helpfulness. (And don't get me started on Jira's absurd take on SCRUM)
Honestly, I'm kinda shocked no major software company has not just built their own and knocked Atlassian out of the park. I'm sure tracking velocity of other companies would be highly...helpful for Google/MS.
> The problem with Jira...is that it isn't for you.
It's more or less one of those enterprise software packages that will be depended upon in larger orgs, because "nobody ever got fired for choosing $VENDOR". That sort of software tries to do a bit of everything, provide lots of features and customizability, sometimes at the expense of being more complex, bloated and slow.
Most people working on their own projects, when fully in control of the decision of what software they want to pick to best suit their own direct needs, might settle on something like Trello or even Kanboard instead. Personally, I self-host OpenProject because its features are a nice fit for my needs, even if it's still a bit sluggish (Rails app, limited hardware resources). Honestly, the performance of Kanboard was blazing fast when compared to anything out there - which is in no small part thanks to how focused and minimalist it is, which in some cases will be exactly what you'll want.
As another good example, I'd also put something like the Oracle database in same category: there will be many projects out there developed around it, as well as lots of knowledge, training, as well as entire professions built around it. But most people won't necessarily reach for something like Oracle XE for their own personal projects, they'll instead pick something like PostgreSQL or MySQL/MariaDB, because both of those are a little bit simpler to get started with and keep running, while still provide sufficient functionality.
This is an anecdote, but recently I launched all of the mentioned database options one after another in containers, for some testing. Oracle took around 10-20 minutes to start up an de usable. MySQL took about 5-10 minutes to become available for connections. PostgreSQL needed just 2 minutes. That's even before I get into how much data Oracle created in a container volume meant for data persistence (an order of magnitude more than MySQL or PostgreSQL).
I experienced similar behavior when setting up my own trial/testing license of Jira because I needed to do some integration dev work - with the resources given to it, I found it to be pretty sluggish and creating new issues took multiple seconds, which does get annoying when you also want to edit some of the fields, or have to do it often as a part of your work. Though I don't have exact numbers for that, I'm afraid.
In the case of Jira, how much of that is related to frontend code, compared to backend code / inefficient queries?
I find performance suffers mostly when media assets, advertisments, marketing and tracking scripts etc. come into play. The frontend rendering rarely makes a dent at that point.
Jira is a not very good product, implemented by worse engineers, that happens to be better than its competitors (ironically proving the point I made further up thread).
Jira is a 20 years old piece of software. I'm sure today's engineers do their best with the constraints they have. And I'm sure the 2002 engineers did their best with this period's assumptions and solutions.
I hate Jira as a product, but please don't attack people like that, have you never had to work on a product you're not 100% satisfied with? :/
>I’m sure todays engineers do their best with the constraints they have.
There are two real constraints in the software engineering world: time and money (especially when we’re talking about an issue tracker, a wiki and a repo + CI\CD pipeline).
That Jira and confluences performance remains … not very good, suggests that the engineers are unwilling to, or unable to advocate for, spending the time and money to address this.
JIRA, Amazon, possibly godaddy all predate modern-day tools like React and Angular by at least a decade though; Jira seems to have a custom set, Amazon probably does as well.
But in most cases, front-end technology isn't the limiting factor.
Most of JIRA being slow is the backend not the FE. I've had the same issues but you can watch the backend take 3 seconds to return. The FE isn't much of a factor there.
Try selling React shit to corporates who have corporate malware infested Edge running on overloaded Citrix nodes or the average corporate android that was made about 3 years ago.
We still get <100ms page delivery with server side rendering and lightweight JavaScript DOM overlays. Our React infested competitors, not so much to the point their clients have been shitposting on twitter about it.
I think what you're criticizing isn't react necessarily, but SPAs. React can be used on the server in the same way as whatever SSR solution you're using.
I don't think you are living in the real world. Is Microsoft corporate? React is a first class choice in their frameworks.
React is like nearly any other tool, use it well, and it's great. Well optimized React is lightweight to the client and a joy to test and debug. That said, Web Components are even better, but I'm guessing that's science fiction to you.
Most React applications do not end up like that in the real world. They turn into poorly architected over complicated nightmares, particularly on sprawling apps which is the reality in the corporate space. Not everyone is building hyper-focused single function tools which can be crammed in an SPA type framework. And the users suffer for this.
One of the finest turds I've seen recently is my electricity company's meter reading facility which is an over-engineered react interface for a single web form with two fields and a confirmation box. The whole thing pulls 590k down to do that and takes 5 seconds for the initial page load on an M1 MacBook Pro. That's the real end game for most people. The only reason it's like that is because the people who built it don't know how to do it any other way.
And lets be honest about Microsoft: they do everything from a front end or user interface perspective and randomly discontinue bad ideas about 5 years down the line. Like Silverlight, most of WPF, bits of ATL and MFC, an entire mobile phone platform that got rewritten. And their competing framework WinUI 3 doesn't even work properly. Their own O365 web platform is a fine example of where this turns into a buggy mess. I bet react is dead to them within 2 years on one of their schizophrenic switcharoos. The only reason they're into it now is to capture some market from Electron.
1) MSFT has already used React for far longer than 2 years.
2) They have basically never used the technologies you mentioned (WPF, Silverlight, WinUI). They offer them as UI toolkits that run in their Windows environment and that’s it. Their failure to market and support these technologies is independent of what they do for their own development strategy.
3) They bought GitHub and effectively own electron now. Many of their biggest apps are on electron (Teams, VS Code, Azure Data Studio).
2. Yes they have. Half their developer tools were rewritten in WPF, they offered huge stacks including CRM on top of Silverlight and a huge chunk of windows 11 front end is WinUI.
3. Teams fucking sucks. VS Code is heading in the same direction. I've never used Azure Data Studio.
> Many of their biggest apps are on electron (Teams, VS Code, Azure Data Studio).
Huh? Those are Microsoft's biggest apps? Not, MS Word, the NT Kernel or ... windows 11? The XBox operating system project? Outlook express? Visual Studio? ... Github?
I'll grant that Electron is used by a few teams at microsoft. But I'd be surprised if even 1% of microsoft's engineers worked on products built with electron.
I can look at the javascript of many "big corporate" websites and see they are often a sprawling mess of homebrew code. I'm sorry your electricity company's React website is bad, but I don't think an anecdote is data. Any framework can get abused, not using a framework doesn't mitigate the problem. But trying to update a site that uses a different approach for every little feature spread across many pages, without any idea of what a component is, that's a nightmare. At least you can sensibly incrementally improve React across a site's components with well worn tools, especially as a team.
I don't love Microsoft, but it's for the best they adopt a well known and rounded framework like React, rather than try to invent yet another of their own frameworks, like the ones you mentioned. I don't know why this has anything to do with Electron, since their React push is for their front end frameworks for their main corporate product, Office365 (or whatever it's called today).
Both of them run like shit in my experience. I mean Discord is basically mIRC that looks a bit better with a shit version of zoom strapped on the side.
Same. We've been working on a huge React project for several years. Lots of graphs, 3d models etc ... and it is super-snappy. Only slow part is a WebGL-based chart component that visualizes 2-3 M rows of signal data. We can probably decimate the signal data to improve performance, but that has got nothing to do with us using React.
N.B. No one is using the app from their mobiles. iPad and computers only.
Our reasons for choosing React when there are so many alternatives: prior knowledge, ergonomics, easy onboarding, ecosystem.
Super-snappy for who? You? with a $4000 Mac Book Pro? Even with 6x CPU slowdown in Chrome, that's not enough throttling for these modern computers to test with.
I make this argument all the time and people think I'm an idiot, which is fine. But JSX to me is reason that Svelte and Vue aren't as good. They are faster IMO but with JSX it's nice that you can make a form and then each part of the form can be broken out into separate methods.
The reasoning I get all the time is "Why would you want to do that? That's stupid".
It's just so much nicer honestly. I'm not a react fan at all but that's one thing I miss about it.
Huh? All of the modern web frameworks let you delegate a component to a team and use it. What does react do here thats special?
Honestly, if anything I find react's modularity story much weaker than the competition. In react there's no page-wide state and the story around styling components with CSS is a huge mess.
In comparison, Svelte components feel much more modular & self contained because the styles are embedded with the component in a standard way.
Would you? Most $400 laptops are on 10th gen Intel or such. Thats actually pretty good. A Pentium Gold is actually just on the edge of a modern i3 which in single core. Smokes most 8th gen chips. They are pretty good.
$250 in an Android phone can get you a SD 695 5g these days. IT's not fast per say but it absolutely doesn't suck.
Yeah I agree with the GP. Most $400 laptops come pre-loaded with all sorts of janky crap that make that 10th gen intel CPU run like a wounded animal.
Most users have no idea how to remove any of it. Or, worse, they'll enable all of the preinstalled antivirus programs because they want their computer to be safe. And it gets worse. I visited my parents once and noticed something weird on my dad's macbook air. Turned out he'd gone out and bought Norton antivirus to install on it (!?). Norton installed a chrome extension which replaced the banner ads on every website he visited with their own ads. I manually deleted the extension from chrome, but norton put it right back again after chrome restarted.
If you don't believe me, use performance counters and measure it. Your website runs way slower on your users' computer than you think it does.
Oh I know, but that situation has become less common over the years. Fewer users are buying AV and most AV is getting better so people don’t complain. Users using outdated versions of Windows with IE has a much larger impact (because IE’s JS engine is incredibly awful)
But the point I was making was that the average computer has actually gotten pretty good. Most users use near-latest chrome, most laptops have gotten much quicker.
And that’s before noting that the average cell phone in the US has BETTER js performance than the average computer. Most US mobile users have a modern iPhone that is faster in single core performance than some 10th gen laptops.
It feels like a myth to me as well. We, tech nerds, value "optimized" solutions, "beautiful" code. We buy top-notch hardware, remove bloatware, because we really care about our tools and craft.
90% of the users use shitty hardware. Everything is sorta sluggish on their computers - they boot up slowly, the bunch of crapware in autorun take their sweet time to load & phone home, their wifi us overburdened with devices. Most of the software experience is sluggish for them. They don't care if their web app is sluggish too.
I think if that was the case Apple would be a much smaller company. People buy iPhones because they "feel nice." And the feel they are talking about is performance.
If you are forced to use an app with bad performance (say Teams) you cope. Humans are great at coping. Maybe you turn it off and back on again periodically, or alt tab to something else while it's showing a spinner.
It's true performance isn't a major selling point but IMO that's because most software products are not sold to users. They are packaged with other products, part of monopolies and imposed to users by others.
I buy video games where performance undoubtedly matters. Apart from that, most software I use, I didn't choose, and I'm pleasantly happy when it's not garbage (Outlook, IDEA) and annoyed when it is (Teams, Facebook). In either case, performance wasn't a contributor to my choice: I didn't have a choice.
All the sluggish steps led them to the usage of the web app they need to use, and they need it to be fast. At least, faster than rest of the crap so far. Heck, they may spend rest of the day with this app..
I’m seeing a lot of anecdotes, not a lot of research.
Nngroup used to publish analyses of the state of usability, but I don’t think they have done one recently.
The old ones always showed progress, and that’s also what I would expect talking about the average situation.
Average progress doesn’t mean there are no shitty situations and we should always strive to improve, I just think claims like this are not helpful as they are used to make blanket statements about nuanced situations.
Unless you can back them up of course, and I would still love to see the data if anyone can find it.
I've been involved in quite a lot of usability testing and I'm often positively surprised by the responses. Which is why I'm sort of skeptical when reading such claims. Also because I think user experience overall has improved, by a lot, the standards now are so much higher than the used to be.
I think it almost always comes down to one thing: Can people achieve the thing they want to achieve in a somewhat efficient way?
If the answer is yes there is lots of tolerance for all sorts of crap before people experience it in a negative way.
That means managing the experience. As example a multi minute upload process can be totally fine if handled properly, a .5s delay on an input can make it unusable. My point being; reality is a lot more nuanced than the blanket "it all sucks, and performance is everything" statement, and personally I don't think it's helpful. Unless we can actually look at metrics and assess their importance and how we can address them.
Don't get me wrong; we should absolutely keep trying to improve, especially crafting well made usable interfaces that are a delight to use. Performance is certainly very important, but it's not the be all end all of user experience and atm wrongly used to justify silly points why [my fav framework] is so much better than React.
In my case it's extensive anecdotal experience.
First when I was a budget constrained student with bad hardware.
Of course now I use a really good midrange phone, good laptop and pc.
Then i noticed a stark differences in attitude in the 2 studies I did at uni.
One was more plain compsci. The other more web/mobile design and development.
The later paid absolutely 0 attention to optimisation. Whether it was speed, download size or anything of the sort.
The former treated an inneficient slution as invalid or at least graded lower.
(Note this was in Beligum)
First time I started paying more attention to this where it wasn't when it wasn't in the context of being a budget constraint student was when I did a temporary IT support stint at a gigantic international pharma company and the software was so sluggish it was....insane.
Dozens of people at our facility staring at a slugish webinterface waiting at every action and doing loads of those for every ticket.
It was so infuriating I tried to make a browser plugin to prefill stuff with comon defaults the moment they were available knowing I'd never use it beyond those 3 months. Years of time must've been wasted staring at little loading circles because management did not use the software.
Then when I made native software for a manufacturing industry niche where i was told some suggested db retrieval and prerendering optimisations and such weren't worth the time....And sure. These were lowwage foreign workers using it, it didn't hamper much at all and our time was expensive. Maybe the business wouldn't get the money out of it....but then i ventured to production and notice more than a hundred people pulling the same actions many times a day thousands of times a year ....and see them waiting split seconds or multiple seconds depending on the actions that counted up to combined wasted minutes, hours, days, weeks and I realised what a load of bollocks it was.
Additionally when I helped extend various ERP's I realised the old ones were faaar from great but the move to web based interfaces really didn't do us much favours.
Then I come home and try to help my various layman family members on their comparatively slower windows and android devices and it becomes veeery apparent that this is not just a professional software issue.
Slugish UI libraries on slugish frameworks on a slugish OS with various other slugish apps.
Coming home to a fast pc running Linux and using stuff i write in my free time using C++ or rust or even just various native apps on windows feels like such a extremely stark contrast.
My conclusion is that users won't care enough up to a certain point as studies show
However I do believe that what those studies don't show is that for a good part this is because it's the default for many of them.
They think this is just what tech is and all those countless small waittimes behind actions is normal.
The new Reddit is so slow... after some bingescrolling I often give up due to the annoying loading times and close the site.
I always imagine that many people react like this on super slow websites, but on the other hand it's Reddit and many people don't know which site to visit instead :P
It's because these things are chosen across a perceived axis of "developer comfort/productivity", and UX (if it is considered at all) is an afterthought.
It's not hyperbole, IMO, and this format of rationale is faulty. There are many reasons why technologies and platforms become ubiquitous. Asserting that being ubiquitous means it can't also be miserable for the user is demonstrably false, with almost unlimited examples throughout software history.
However almost certainly ubuitity is one measure or factor in an item's usefulness. I'd also claim Usefulness inversely correlates with miserableness in the mind, but perhaps not in practice :P depending on how boring or miserable useful things are.
In general, I think usefulness overrides miserableness simply because the willingness to do useful things, despite miserableness, is clearly tolerated and performed all across human economies and societies through time. all just depends on definitions
The gulf between "showing up in person and waiting in line at the bank" and "performant web app" covers a lot of ground, most of it shitty and frustrating, and that easily can be many times better than it currently is.
But yeah, I guess you're not waiting in line at the bank anymore.
> Most frameworks outside react still use templates. Even when they support JSX like syntax (aka vue 2.0) the default are templates. Templates are a no go for me. I use them for blogs or static websites, but applications are easier to make and maintain with actual javascript.
I've gravitated away from React towards Vue v3. Templates are working fine, well even. You still use similar amount of Javascript (probably less).
> It's just the useEffect hook. Unfortunately that's a big problem. That hook should never have existed.
Weird. useEffect is like the archetypal hook. The problem it purportedly solves was one of the main arguments they made for hooks existing in the first place -- https://reactjs.org/docs/hooks-intro.html#motivation. They just implemented it in a clunky way, and actually the problem could have been solved in an OO fashion without going to hooks at all, but now everything is a fucking hook.
>Weird. useEffect is like the archetypal hook. The problem it purportedly solves was one of the main arguments they made for hooks existing in the first place -- https://reactjs.org/docs/hooks-intro.html#motivation. They just implemented it in a clunky way, and actually the problem could have been solved in an OO fashion without going to hooks at all, but now everything is a fucking hook.
There was (and still is) a real problem in react with composability. Which they tried to solve with mixins, then HOC and then hooks.
The three main hooks are useState, useContext and useEffect . useState and useContext are very straightforward and an overall improvement on their previous counterparts. useEffect was an improvement over mixins, but it was a worse solution for class component lifecycle methods.
It was fairly obvious that useEffect had a lot of problems from the get go, but it was deemed worthwhile to add so that functional programming proponents could have state without classes and to finally have a way to use composability without the horribleness of mixins and hocs (which were worse then useEffect).
The real problem is that useEffect has it's own problems, and while we no longer have the old problems, the new problems might be worse.
Sorry. The biggest problem is that useEffect's mental model is based on data change and not on events.
So instead of "do something when this action/event happens" we get "do something when this data changes". Which ends up being abused a lot, as developers who aren't familiar with this mental model (which is most of them), tend to lump up every action into a data change.
So instead of something like (contrived example):
openAlert() {
alert("I'm an alert");
}
return <button onClick={openAlert()} />
people do:
const [alertOpen,setAlertOpen] = useState(false);
useEffect(()=>{
if (alertOpen){
alert("I'm an alert");
}
return ()=>setAlertOpen(false); //if they even remember to unregister
},[alertOpen])
return <button onClick={()=setAlertOpen(true)} />
Beyond that there are multiple other problems:
- the fact that useEffect (and hooks in general) is order dependent and can't be put inside branching (so I can't start an affect after an event happens).
- the fact that inside useEffect you read the data of the previous render is very unintuitive (I.E. your data is stale).
- the need to always put all your dependencies that are used inside useEffect in the dependency array explicitly - which can be even harder when dependencies are dynamic - is also a problem for many.
There's probably a few more, but that off the top of my mind.
The fact that there needs to be several eslint rules in order for people to not footgun themselves constantly is quite a red flag on it's own.
I think your example was good, but I disagree with your conclusion. In your example, the hooks version renders the UI based on data/state. In the non-hooks version, the state of the rendered UI depends on ephemeral events and the order they were dispatched. The hooks version is more easily tested and it's easier to reason about as a developer. It conforms to the mental model of a function (props, state) => UI. The non-hooks version would look like (props, state, actionHistory) => UI, where actionHistory is a list of all actions the user has taken since the app was initialized. With that function, we can't reproduce UI, because we don't have actionHistory (since the events triggered by the actions has not been recorded).
And are you sure the data in useEffect is stale? I don't think it is, the documentation[0] seems to suggest that it uses the current closure.
> People tend to compare these frameworks on things that don't matter - often it's performance.
Performance people get offended when they hear things like that. I imagine what they will tell a person who says something like this is to:
- Look at the traces. Real metrics, on real devices that users have, not the one that developer has.
- Consider either large contentful paint (will likely be subpar with client-side rendering) or first input delay (will likely be subpar with server-side rendering). Consider, too, the new interaction-to-next-paint metric (rumoured to be bad with all js-heavy sites)
If these metrics look good, then great; carry on doing what you are doing. If they don't look so good, then, they would say, reflect on whether what you are building is losing the business money by driving users away.
My reading is the opposite. Basically all real end-to-end UX (actual performance included) depends on a collaborative effort.
Someone mentioned that React is slow, it might take 200ms to update many elements.... and? Unless someone is making a fast-paced interactive game of DOM elements, it doesn't matter. Structuring the UX in a user friendly way matters infinitely more.
Structuring the UX in a user friendly way matters more, that doesn't mean random 200ms lags are OK. As you said, performance is UX too.
I hear normal, non-tech people with average hardware complain about "lagginess" of their machines all the time. And usually the only application they use is Chrome. They won't say that they had a 200ms lag when they clicked on a button, but the overall experience degrades when things are slow to respond. And when you sit that person in front of a good, optimized, snappy application, they will sing praise. Not particularly because of performance, but they will enjoy using it more, and they won't be able to explain exactly why.
You'd think that with the ridiculous amounts of money software engineers are paid to do what they do, they'd be able to swallow slightly more difficult collaboration and developer experience in order to deliver a more quality product. Forgive me for being harsh, and I don't mean this as directed to you (I don't know you), but our industry behaves like a bunch of babies.
Aside: if you're making an interactive game, you have 16ms to respond and render, not hundreds. In 16ms, modern games dispatch draw calls for millions of triangles, do AI, physics, netcode, level streaming and other bookeeping. Yet the teams there collaborate just fine.
Random 200ms lag is different than showing a new panel full of elements.
I'm aware of those complaints. 95% is when people are using a thermal throttled old device, while the app in question is trying to smoothly animate a complete clusterfuck of a webpage (for bonus points it's usually in some god-awful WebView in an app).
It's not simply displaying new checkboxes, inputs, labels, buttons, it's multi-megabyte images with fancy CSS effects and so on.
> They won't say that they had a 200ms lag when they clicked on a button, but the overall experience degrades when things are slow to respond.
Of course, no questions there! But it's not because the "framework is not performant enough", it would be slow even in vanilla JS in 95+ % of situations.
> And when you sit that person in front of a good, optimized, snappy application, they will sing praise.
Yes. And it's because you say to the client/designer/productperson that hey, if you want snappiness even for the 99th percentile of your users (ranked by hardware), then let's test on that device, and let's forego that nice animation that you saw in that native app on your friend's iPhone 15 ÜberMaxPro.
And, not surprisingly, many of the aforementioned culprits will say "I want that shiny thing"
> but our industry behaves like a bunch of babies.
I don't think you're harsh at all! And I agree. Many IT workplaces went all-in with the infantilism. (Daycare for autist-savants! Colorful open-office with a playroom, maybe even a ball pit! You can't concentrate today? Don't worry, just play some table tennis, and try it again tomorrow! -- Contrast this with the endless office gray cubicle farms of the engineering departments ~50 years ago. Which is probably the other extreme of the spectrum. And I believe there's a healthy middle ground. Well maybe slacking off on HN is not exactly part of it.)
> Yet the teams there collaborate just fine.
The games industry is famously not in a "fine" place, I'd say :) But yes, of course, they have a clear target, and even if the process requires some blood sacrifice for the crunch times, it works, sometimes. Sometimes we get buggy things like Cyberpunk 2077, which was less-than-optimized for some target platforms.
React isn't defenseless in the performance department. If a naive implementation takes 200ms to update many elements, there's usually an approachable way to speed it up!
The performance "disadvantage" of react (compared to what? SolidJS? handcrafted JS? some WASM thing?) is so small a user won't notice it in most apps in most places even if you don't actually optimize things.
Then indeed, abstractions a team can agree on matter more. Getting state management right matters. Hiring people and getting them productive quickly matters. Those are strong points in favor of React and even Angular, to an increasing degree for Vue, Svelte and others.
Experience from using React for many years tells me. Rarely have I needed to optimize anything related to react to make something visibly snappier, and most of the time it's not really React's fault.
And there are some benchmarks that show SolidJS and some other things are faster than React at specifically what React is doing (like dom manipulation/reconciliation etc).
If a page is taking too long to render or interact for regular web usage, it's almost certainly not because of React. Clearly there are extremely performant applications using it at the highest levels of scale and complexity (Facebook, Twitter, many others).
Performance mostly matters depends on the target audience.
For example, if you have a React-based wrapper around some SAP Gateway calls to replace the standard SAP UI then the user doesn't have much say. Because of the perceived better UX. The users of the solution inside companies (think multinationals, larger government etc) your call agent that use the React-based SAP portal can't really say I am not going to use it. Hands are tight.
The only time performance really matters when you have paying customers
Your dislike for ‘templates’ is much more a matter of personal preference than you’re letting on. Using language like “still using templates” makes me think that you don’t see any valid opposing view.
I do not like JSX. It’s not worth talking about why. It’s not an argument I want to have. But framing non-JSX approaches as objectively inferior is not in tune with the reality, being that this is something sensible people disagree on.
It’s pretty hard to get more “this is my opinion rather than a statement of objective fact” than this.
> I do not like JSX. It’s not worth talking about why. It’s not an argument I want to have.
Ok.
Um… well, it’s hard to have a discussion if you won’t talk about it…
…but, “code” templates allow autocomplete and type checking in a way that is an objectively distinctive superset of text templates.
It’s because they are code.
A template is (almost always) a weakly typed DSL. Written, ignoring all the history of language design… by a bunch of folk who don’t really know how to write programming languages. …and, they. Are. Bad. Not always… but often. …because writing a language is hard, and because (reason) you can’t ever use an existing template language. Oh no. This framework has to have its own unique one, because otherwise it doesn’t integrate tightly.
Do you like DSLs? Or do they just hide the complexity somewhere else? What if the DSL is bad, not orthogonal in its feature set, poorly implemented …but cute, and useful for a very very narrow use case.
Isn’t the main critique of react that it hides complexity by moving it from one place to another?
Don’t you think it’s a tiny bit ironic that all the other templates based languages with their custom template DSLs are doing the same thing?
Anyway; I think it’s fair to evaluate template languages as what they are: DSLs.
JavaScript is a better language than most template languages by a variety of metrics. Other languages are better than JavaScript, absolutely… but, never, have I seen a template language that is.
You can love declarative configuration all you want, but it’s very very difficult to argue that just because you can make a mess with procedural approaches that they are worse; because they are a strict superset of what’s possible using the declarative approach.
…so sure. I don’t but “JSX is easier to maintain”, but it’s distinctly superior in capability.
JavaScript is a better, but JSX is not JavaScript. It reuses many features from JavaScript, but you still need some sort of translation (compilation) step to make it useful. In this sense it is not really fundamentally different from any of those what you call template languages.
You can argue the fact JSX better integrates syntaxes from a proper programming language makes it better than other templating languages (and I’m not going to try persuading you otherwise), but the “JSX is better than template language because it is not one” stance you’re implying won’t help you win any arguments.
That is literally the difference between JSX and most other template languages. Look it up.
The template syntax is converted to literally code and evaluated. The <> are just syntax sugar. How did you imagine the inline code works? The in-line function declarations?
Did someone invent a mini-subset of JS as DSL and a custom runtime…? Don’t be ridiculous. They did not. JSX is literally a thin wrapper around actual code.
Template language being translated to code is nothing new and certainly not unique to JSX even only when you consider frontend JavaScript frameworks. Vue has been doing that ever since single-file component was a thing. You need to look up things, please.
I have no idea why JSX wouldn't be considered a DSL template language?
I guess there are specific features you find compelling: it's typed, has good tooling for completions in your editor?
These exist in other template languages, and ones that transform more readily to HTML (which is the goal, don't forget).
Maybe you also value that it has a straight-forward, well-defined transformation to javascript?
That's OK, but since HTML is the goal, it doesn't seem right to optimize for an intermediate representation. To me it's a weakness of react that you have to work with HTML as javascript (which JSX mitigates fairly well, but is hardly ideal).
Strongly agree. I just don’t get the hate for JSX.
JSX is objectively better than than the scores of templating systems out there. You get much more: type checking, use of JS for logic, and no need to learn yet custom arcane syntax. If anything, I think JSX is not used and supported enough.
In the general sense, JSX is just syntactic sugar for function composition. That it works well for html-style components is a side effect; it could certainly be used for more than that.
I wish languages like Typescript would support JSX natively, with absolutely to dependency on any React-like library. Let me declare a function using JSX, e.g.,
Strongly agree. I just don’t get the hate for JSX.
JSX is objectively better than than the scores of custom DSL templating systems out there. If anything, I think JSX is not used and supported enough.
In the most general sense, JSX is just syntactic sugar for function composition. That it works well for html components is a side effect; it could certainly be used for more than that.
> When using React I usually just use MobX and everything just works.
MobX is signals library. In other words, you are already using the signals way of doing things if you mostly manage your state with MobX. I still use MobX as well if I think I can't use SolidJS.
SolidJs if you haven't looked has MobX-like tools built in, computed, autoruns and all the same tools, it triggers "renders" when one of the signals changes. In reality it doesn't have renders, because it's not based on VDOM, but it makes it look like it does.
However I like to keep my signal library separate, I would wish SolidJS had separate signals library I could use elsewhere as well.
Also SolidJS is big library and framework by now, it comes with risks if Ryan Carniato were ever to loose interest.
Edit, I also found that Ryan has created an example of MobX and JSX without React, it's a good way to demonstrate that React is not as important with signals libraries: https://github.com/ryansolid/mobx-jsx since you know MobX that example probably makes sense.
I haven't used SolidJS, so I can't comment much. But Signals have very good developer ergonomics. But from my experience other frameworks that use them come with drawbacks that I don't get with react. So MobX+React works better for me than - let's say vue.
From a brief look at their website, the downsides for using SolidJs for me seem pretty big. At the very first example, if you change it slightly you can see my problems:
const CountingComponent = () => {
const [count, setCount] = createSignal(0);
const interval = setInterval(
() => setCount(count => count + 1),
1000
);
onCleanup(() => clearInterval(interval));
if (count() % 2 == 0) {
return <div>Even count value is {count()}</div>;
}
return <div>Odd count value is {count()}</div>;
};
1. MobX let's me use objects without additional syntax (createSignal, count() instrad of just count)
2. The fact that the component does not rerender and that my code does not automatically change between even and odd text means I'll probably need to have an additional mental model for writing SolidJS components. Using React+MobX I just write as I would write any other function and it'll just work (There's magic involved, but manageable magic)
There was a debate very recently between SolidJS and React communities over "internalized react-isms" like difference in behaviour you've pointed out. I think it's React that are doing the weird thing and calling your whole function again when one piece of data changes, but I do like having the ability to return early.
> People tend to compare these frameworks on things that don't matter - often it's performance.
Performance on the end-user device, especially if you're just under/over certain thresholds like 1sec to switch "tabs" or whatever you're using, does matter. Especially if you're trying to get people to buy stuff.
I wish all developers had to routinely try their products on a low-end 2-year-old smartphone. That would take the discussion of whether performance matters to a more informed level.
Its is actually sad just looking from a hardware endpoint. A 2016 iPhone 7 has an advanced 5 nanometer CPU. That is really powerful when looking at the grand scheme of things. Yet most react "websites" will completely obliterate it and make the phone get blazingly hot. I do this for fun a lot when browsing the web: when a website makes my phone literally melt, I check its stack on my PC and sure enough it is almost always React paired up with Redux. These performance apologetics are sad.
In my opinion, React was pretty much complete without the introduction of Hooks.
Shifting from the previous Component-derived mental models to Hooks was a cause of many runtime issues in at least 2 companies that I worked for.
Unfortunately, React went from less-capable and more understandable to more-capable and less-understandable model. But yeah, that's just a newbie-coder take.
> When using React I usually just use MobX and everything just works.
Same. React as a UI library is great. React as a state manager (hooks) or a framework is (hooks or hooks+next) is not good. Writing and fusing business logic to a framework is always a bad idea
> But I choose frameworks because of developer ergonomics.
I understand that sentiment, but it's part of the reason why computers today don't feel faster than in the past and why we waste sooooo incredibly much energy.
I don't think the sentiment in itself is harmful. I agree with the conclusion, but I believe the problem is, there is so much accidental complexity built into this space. Path dependency makes it hard to get rid of it, so rational developers and start ups end up contributing to the problem.
My personal bugbear about pretty much all web frameworks discourse is universally stated things like:
> People tend to compare these frameworks on things that don't matter - often it's performance.
Performance matters in a lot of contexts. If you’re doing complex stuff performance matters. If you’re a public facing site depending in search traffic performance matters.
I’ve ended up disliking React simply because it’s become this one size fits all solution that 90% of web development goes through without it ever being necessary. There’s nothing wrong with React itself but it’s often applied badly.
I don't see a problem with useEffect. It releses you from thinking about component lifecycle.
Conceptually the body of your component runs on every render. If you want to have some effect on your component not running in sync with that then you have useEffect to set it up and clean it up not when the component is mounted, unmoutend, rerendered ... just when the stuff you are interested in changes.
The way I look at it - the majority of value with blogs and static website is content. Hence the majority of change is of content.
For apps the majority of value is functionality and that's where a lot of changes happen.
The main problem of maintenance happens where there is the most change - in JSX programming (I.E. functionality) is a first class citizen and it lends it easier to change.
With templates content is much more of a first-class citizen.
Of course this is all in the margins, you can write blogs/static sites well in react and applications well in template-based languages. The tradeoffs are just a bit skewed in favor of each, and it mostly manifests when you don't have time to be disciplined about changes.
This thinking is why most SPAs are utter shit for the end user. Most developers are so happy about their ergonomics and how cool their tools are and don’t care at all the application uses 200M on your browser and every key stroke takes 200ms to show in an input.
This also happens in the backend, but the difference is that the company país the price in the form of more infrastructure. But in the frontend is “free” so why care at all, right?
that's a problem with the choice to go spa instead of ssr or static, not the choice to use a framework with productivity benefits. with every major meta-framework working seamlessly with the popular serverless hosts, it's a wonder anyone takes spa seriously in any performance-sensitive context
You might also be interested in checking out Vue 3 (with the Composition API) and Pinia, it's a pretty nice setup that feels similarly nice to how working with MobX is and even supports TypeScript.
While I mostly stuck with JavaScript, personally I found the setup more convenient to use than working with hooks in React, and Pinia is also more like MobX than something like Redux, in that you don't have to work with too much accidental complexity for relatively simple setups. Sadly I don't have examples from that project, because it was proprietary, but the linked docs are nice.
Thanks, I'm sure Vue 3 is a lot better than v2, but I deeply appreciate TSX for its refactoring and type checking capabilities. Vue does support TSX but it isn't a first class citizen.
I played with Vue and svelte and now a firm React user, mainly due to its ecosystem, for most products the slowness of React does not play a major role at all for me.
1) JSX - It's terrible. Svelte, Vue, Riot... they all got it right. JSX, mixing a weird syntax of HTML and JS together is just inferior to HTML with additional markup.
2) I don't know why but every react project has crazy levels of abstraction. Everything is 15 layers deep and making any sort of change requires way too much effort to navigate 15 files and code reading to make the most mundane changes. Other libraries seem to suffer from this to a far smaller scale.
For one you don't have to write an arbitrary key={item.id}. What if you don't have a unique ID? And even if you do, it's just busywork.
Then, what about conditionals? Or slots? Or classNames instead of classes? The saving grace of JSX is that it allows the creation of multiple small components inside a single file.
> The saving grace of JSX is that it allows the creation of multiple small components inside a single file.
That's definitely not the saving grace of JSX. As I said, every react project is soooooooo overly abstracted into the tiniest little components. It's no wonder people /think/ react is slow.
i dont have a dog in this fight but JSX is PHP all over again with additional "creative solutions" where html and js keywords clash. but they both make html less readable in different measure for different people. please carry on with the arguments :}
For what it's worth, I like the syntax of Lit. There are a couple of magic symbols ("@" for method, "." for property); but otherwise, it's plain javascript.
The DOM output that Lit produces, peppered with magic comments, looks disgusting though :-(
JSX forces you into small tiny components because anything of any decent size becomes unmanageable. There's way too much mixing of JS into the template.
Vue you can do
<button :disabled="!isFormValid">Submit</button>
In React I've seen people do:
if (!props.isFormValid) {
return <button>Submit</button>;
}
return <button disabled="disabled">Submit</button>;
This is just an example, obviously you can write this better in React. My point is there's /always/ so much conditional markup like this in every react project I've come across or worked on.
Edit: I donno how to format code on here sorry. (oh figured it out, bunch of spaces)
Trying to be fair here, but what about vue makes it less likely that you won't put the same conditional logic into your vue template? If it's just impossible, then you're saying the framework is more limited, which is fine but sometimes you want flexibility.
This seems to be a 'best practice' issue as well that can be avoided through PR review. My team has been putting logic more and more into local hook files to keep components clean.
There's nothing inherently stopping people from writing clean react projects. But I've never seen one. But watching people fumble around trying to find where they need to make a change when things are so overly abstracted, and STILL try to justify that react is good, is baffling.
People break tables up into ~50+ files. It's crazy, and everyone does this, and its an absolute nightmare to maintain. Its 100% engrained into react culture that this is the right path forward.
React will never get better if people accept over abstraction as the right path forward.
So, I have not used React more than a tutorial here and there. Same with any of the other SPA libraries.
I do not understand why everything needs to be a single page application. Sure, my current employer is behind the times in the technology we use, but honestly, we survive just fine with server side rendering and plain, ol'boring, vanilla Javascript and a little JQuery here and there.
Of course, some things we have written are difficult to maintain at times, but I doubt any other library would have really made it simpler (more of an issue with the requirements than the technology). Abstraction is simple, for us at least.
I'm surprised you see that as a disadvantage, for me that's always the biggest advantage of JSX-style syntax! I don't want huge components that do everything, I want components to do as little as necessary to be actually useful. It's the same as if I were writing functions: keep them fairly small, make sure they're doing a specific thing usefully, and then compose them together like Lego bricks.
When I was doing more Vue work, this is one of the things that I struggled the most with, that splitting one component into two components required a load of boilerplate and a whole new file. (And that itself was a big improvement on Angular, which usually had multiple files doing different things, at least when I was last using it). This inevitably meant that I'd try and fit more and more stuff into a single component until it the pain of maintaining it was greater than the pain of splitting it. (At which point it would usually be a lot harder to extract the would-be child component than it needed to be, because I'd left it too long.)
I think the rest is mostly just syntax preferences. Like you say, you can write bad code in both cases, and I think a lot of it comes down to which matches better to your mental model if what HTML generation looks like. But being able to easily start a new component, just like starting a new function, is such an important benefit of JSX, for me at least.
> I don't want huge components that do everything, I want components to do as little as necessary to be actually useful
Having lots of tiny components makes it harder to see the big picture.
Too big and too small are both bad, there's a balance you need to find. Components should be small enough to fit in your head, big enough to represent ideas. The difference is that it's natural for big components to be broken down into smaller ones when their size starts to cause pain. But nobody goes around merging smaller components into bigger ones to make them more readable. When your components are too tiny people just suffer through the pain and develop Stockholm syndrome.
> I'd try and fit more and more stuff into a single component until it the pain of maintaining it was greater than the pain of splitting it
I understand that it seems painful, but this is actually a great workflow: it forces the decision to split to be based on the real pain, not on your fantasies about future pain. Pain is a tool that helps you make good decisions. In that sense React is like Perl: easier to write, harder to reason about.
To a certain extent, I agree that you also don't want overly small components, but it feels a lot like the debate about function size. Sure, you don't want to wrap every statement in its own function, you want functions that are big enough to actually do something useful, but as a rule of thumb, smaller is better than larger.
This isn't a theoretical concern either. Like I said, I've had this issue with Vue before, and component sizes just bloated to the point where many pages were just single, chaotically interwoven components with dozens of state variables that theoretically were never used by each other, but in practice tended to be shared accidentally or out of short term convenience. At which point all bets are off and every bug becomes an exercise in figuring out what's going on.
That's not to say that that's a Vue-specific problem, because I've also had that issue in other frameworks, including React. But far less often in React, because it's much easier to deal with the pain when it starts with a simple refactor, than dealing with it a year and several new features down the line when everything is tangled together like a headphone cord in your pocket.
I also love small and well thought components. But as an engineering lead and manager it’s a lot of effort wrangling devs to do so. They always start small and then overtime converge on multiple return statements full of huge amounts of inline JS.
I've been enjoying SolidJS recently, and due to framework limitations, it is generally impossible to have multiple return statements, which I think helps a bit here. The signals stuff also lends itself really well to writing code that operates only on state, and then plugging it into a thinner, dumber DOM layer, so it's easier to compose pieces together. It's like hooks or the Vue composition API, but moreso? It's difficult to describe.
That said, SolidJS as a whole requires a completely different mental model of rendering, even if it does look superficially similar to React. It's also a much smaller ecosystem, with less documentation, so getting to grips with it is that much harder. Very rewarding, but probably not ideal for everyone right now.
> one of the things that I struggled the most with, that splitting one component into two components required a load of boilerplate and a whole new file.
> JSX - It's terrible. Svelte, Vue, Riot... they all got it right. JSX, mixing a weird syntax of HTML and JS together is just inferior to HTML with additional markup
Hard disagree. Every time I work with Svelte\Vue I wish it had JSX, which is way superior to templating because:
- Creating sub components in the same file is super important. Going to a separate file, copying all the imports, writing emits, then going back and importing that file is too much hassle for a simple case where you have a carousel with cards. Refactoring is slow, components end up bloated.
- Passing down functions is more convenient than emits. For all the talk about how svelte is boilerplate free, it's equivalent of passing down a function and calling it is at least 5 extra lines of code.
- Passing down JSX elements is more convenient than slots. Every time I need to remember how to do named slots in vue\svelte I have to read documentation, while in React the mental model is obvious.
I can’t stand JSX either - it’s using JavaScript to render HTML templates, but it’s not valid JavaScript or HTML. I much prefer libraries like Lit that use tagged template literals for rendering component views - you write real code in the actual language the browser understands, no extra transpile step needed.
> People tend to compare these frameworks on things that don't matter - often it's performance.
I think I reflect the entirety of the user base of the internet when I say "fuck you" (not you in particular, just the trend of shitting on performance so we have apps running like it is 70's and tape drives on our gigahertz CPUs) here.
People laugh at web development, especially the frontend, for changing libraries every week but you read a thread like this and everyone is so sure that React is a bad library and we should be using some newer library instead.
I work with React daily and it has issues, but I find most issues can be worked around without much trouble. It's easy to hire people, onboard people, and if there's an issue you can be fairly sure that someone else out there has had an issue too and there's a solution to be found.
I'm not in a hurry to replace React, but I don't need to. React is stable enough to rely on in my honest opinion.
Yes they'll know the React part. It's the Redux/Mobx/React Router/whatever snowflake libraries you chose part that will be more difficult. I really don't like incomplete solutions personally.
> Don't use those...then an additional 4.9% can be handled with jotai...
Needing Jotai on top of React's defacto state management is the issue. TFA talks about an ecosystem of libraries that attempt to fix React's shortcomings. Pure React does have undeniable shortcomings like proper, non-brittle routing.
I agree with you about routing. Something so core about building web apps should be treated as a first class citizen of the ecosystem.
I don't think jotai adds a lot of complexity though, and like I said most of the time you don't need it. It just makes syntax a bit nicer to read and write, but you could do it with context if you really wanted to.
Its all about preferences, I tend to prefer seasoned devs who have had the chance to try different things and form their own opinions. Someone who has relied on framework magic they don't understand through their careers tend to be less resilient to change
All of these libraries are standard and easy to approach; when I was freelancing, my onboarding on React projects was incredibly quick, and I pushed bug fixes and features within the first few hours of joining a project. React's productivity boost is often overlooked; most developers should easily understand a fairly well-written React component connected to a Redux store.
I would like if the industry had less React domination. React is a bit like the IE8 of frameworks. It might not be the best choice for individual cases, but you have to learn its quirks as a developper since all the industry uses it.
But if we don't replace it, I appreciate if React introduced fine-grained updates and changed their attitude towards performance. I think as an industry, we have been pushing the "optimization is the root of all evil" statement beyond it's limits and now all software is super slow (except maybe games and some nice things like Excalidraw).
As I'm writing this, I noticed that Excalidraw uses React, so I wonder what's their secret sauce. Maybe recoil?
My position isn't that we should be using a new library per se. It's that we should be more selective about what 3rd party code we use and espescially what we ship to end users. React has tended towards a kitchen sink approach and this is exacerbated by initial design shortcomings/decisions i.e. no built in state management or method for encapsulating styles has lead to a deluge of libraries that promise to fill the gaps, none of which quite work with one another. This I guess is why we've seen the rise of meta-frameworks like Next which fill this gaps in a predictable way. But these just meta frameworks just shift developers another step further from the underlying HTML/CSS/JS making it harder to debug things and harder to fix issues when you stray from the framework's happy path.
(All that said, I don't blame people for choosing React for certain classes of projects, the economics of hiring new devs, the relative maturity and stability , the large community etc all make for powerful incentives to choose React)
Sorry, reading this back I see where that might be confusing.
It's a few days later now but I think I was referring to React in the round as deployed in the real world, the community norms etc. rather than just the core library. In my experience the way that React projects tend to develop is that "tried and tested" libraries get added to to solve particular issues, most commonly state and styling (codified in meta-frameorks like NextJS etc.) but also UI transitions, wrappers around common non-react libraries like Leaflet or threeJS etc. The reason being that it's actually quite hard to sensibly integrate vanila JS libraries into a React code base so if someone has done the hard work why would you not use that. But of course this comes at a cost. More recent libraries (in my experience svelte but i understand this is a common feature) mitigate the issue by 1. having a builtin approach to state and styling 2. making it easier to drop down to the underlying HTML/CSS/JS without making a mess.
The claim that if you used React for the past 6 years meant you used a single library is almost certainly false.
Because what React is as a library today, with functional components+hooks is completely different from what React was when it first came out, with class components.
React is quite clearly a name that incorporates at least 2 distinct libraries which are supposed to be fully compatible but they’re not…try using a ref for a functional component.
The existence of these 2 libraries under the same name means thst documentation is also increasingly confusing. It also
means that both libraries are probably making compromises
So they’re still compatible with each other on the surface.
Except React decided to change to hooks and break all their docs. And Vue decided to break things with ver 3. And then there's Next. No, Nuxt. Wait, no, it's Nest. Or Sveltekit. It's not frontend anymore, it's more like frontend on backend, but not quite. No, is both now, we got interactive islands. And web components. Oh and wasm. Or was it blazor? And we have webpack. No, Vite. Or Parcel? Almost forgot, it's esbuild this week, innit?
But other than that, yes, frontend is pretty stable now.
I think you've accidentally proven his point. Half the things you've mentioned have been around for half a decade at this point, and pretty much all of them have existed for at least 2+ years.
Frontend is still a fast moving space with a large ecosystem - and I get for some, that's not ideal. But this 'frontend fads' meme isn't really reflective of the current reality.
Rust, which is the greatest new hotness in the backend world is from 2015.
Other major languages in the backend world are at least 2 decades old (C#, Java, Python, C++, Ruby, etc).
C# with the .Net framework is an interesting example. Microsoft realized their original windows only approach was a dead end. They created .Net Core. But someone moving from .Net framework to .Net core didn’t have to relearn much at all, beyond initial config/bootstrapping, and which subset of the APIs had been implemented, because MS completed the implementation in stages.
On the flip side you have React, where you’re ostensibly using the same library for a decade, except halfway in between they made a change which completely flipped how developers weee supposed to use the library.
I mean, that's just a laundry list of buzzwords. Yes, these are all things that exist, but that doesn't mean anyone has to learn them or that they're even used in a significant number of real-world codebases. It's like complaining about web development in Python, because there was Django, then Flask, Bottle, CherryPy, and now FastAPI, or Starlette, or Starlite, and Pydantic or attrs or dataclasses or whatever else. In practice, there are some fairly clear ecosystem best practices for the majority of cases, and a bunch of different alternatives because every ecosystem loves trying out different ways of doing things.
I've been feeling the same sentiment as the author.
Having worked on 3 sizable React projects now (all started before I arrived), I can only conclude that beyond a toy phase -- once you have many hands working on React and *particularly* once you start managing sizable state -- there is only pain.
The most recent case resulted in spending quite a bit of time explaining to a peer why we were experiencing an unexpected side effect and redraw and explaining how `useMemo` and `useCallback` actually need to be used [0] and made me think of Stephen King's Langoliers.
It occurred to me that "React is the new IBM" [1] It has become so dominant in the market that no one can get away from it. But that also means that it can no longer innovate. Andrew Clark's twitter post *acknowledging* that signals and fine-grained reactivity would be better for performance but that the React team doesn't care pushed me over the edge of frustration.
I think that React finds itself not too far off from where IBM was at the micro-computing revolution. IBM had become too beholden to its market and too arrogant in their own success to see their own downfall.
The traffic and feedback on the second article is an indication that there are a lot of folks out there who are really, really dissatisfied with the state of React.
Functional components and hooks were a huge innovation to class components and significantly improved the ergonomics of the library. That was only a few years ago.
The team is actively working on RSC (react server components) which will have a similarly large impact on react's capabilities.
Frameworks like remix and next will be able to leverage and build on this to create even better systems for building apps.
The whole signals blow up event is weird to me. Seems to be a loud and extremely small minority making a fuss around it.
IMO React continues to dominate over others (Vue, Svelte, Angular, Solid etc) because its just better - it embraces JS (no v-for, ng-for, non JS language) and strictly sticks to the idea that the view is a function of state.
All blow up events come from a loud and extremely small minority. But whether they are making noise or signal, does not depend on number of people!
React continues to dominate others because it meets baseline criteria for a js framework. And has corporate backing while Vue doesn't. Angular 1 was also popular because it was average js framework with google's backing before angular 2.
Implying that React remains popular for purely it's technical merit is utter nonsense. Because if react was really technically better, then no one would have migrated to Vue, solid and svelte or angular for that matter
> All blow up events come from a loud and extremely small minority. But whether they are making noise or signal, does not depend on number of people!
Fair, this instance is 100% noise imo.
We're engineers - we should be able to judge when something is silly.
> React continues to dominate others because it has corporate backing while Vue doesn't. And angular was popular for the same reason before angular 2.
I have never heard anyone in the last few years say react is better because it's backed by FB. I pick it because it embraces JS (unlike Svelte), doesn't reinvent the wheel (ng-for, v-for), and has a track record of maintaining backwards compatibility (unlike Angular re Angular vs Angular 2, hey its google what else should you expect). Class components continue to work 100%. Angular is backed by google - a much bigger company than FB and its nowhere close to as successful.
> Implying that React remains popular for purely it's technical merit is pure nonsense. Because if react was really technically better, then no one would have migrates to Vue, solid and svelte or angular for that matter
Some companies like to experiment, or have very unique challenges for which they find other tools better. I avoid Angular and Svelte - both have made such odd decisions. Some people do just prefer one tool over another! There will never be any set of capable tools where 100% of people select the same one. That's the variation of life.
Per the article's comment on forms and react and the messiness that ensues, well we're engineers. We can't expect a single library to solve every problem. We should be responsible for avoiding bad patterns like throwing from state into react state. It's 100% not necessary and should be kept separate.
You picked it because others before you had already decided and that was based off of the facebook name and backing. No one expected facebook to take such a pr hit over the last few years but ignoring why it become market leader misses the angular breakage event where everyone flocked from Google's framework to facebook's framework.
The reasons for not using other frameworks seems copycat without logic. For example vue uses v-for I don't want to have to learn a handful of obvious tags like v-if or v-else but then choosing react which has adopted jsx something that requires converting standard html and learning more to get you to the same place.
FB's reputation has no bearing on my choosing react vs svelte vs x or y or z.
I continue to pick React for projects because it's better than the alternatives - not because others before me have picked it and I'm just copycatting.
I can understand why some dislike JSX. I happen to think it's a great abstraction that elegantly combines the declarative nature of HTML and the power of JS.
It's always worth noting JSX can and is used in libraries beyond React (hello Vue!) which further demonstrates its composable nature and flexibility.
AngularJS and Angular (what you referred to as Angular 1 and 2) are completely different frameworks. It’s a branding issue, not a technical one.
Angular, from version 2 to 15 in the past 8 years, has been completely backwards compatible, and even stayed on the same paradigms. Angular code from 8 years ago looks almost the same as modern code. Which is much more stable than react’s codebase.
I mean, for a single version bump (Google called it Angular 2.0) to render not only the code not migrate-able, but the entire paradigms on which the framework was based on is basically unheard of in an enterprise-targeting framework.
AngularJS and Angular are really the same product. Angular 1 turned into Angular 2 turned into Angular 15. That’s far from different frameworks, even if in between versions you’re essentially learning a new framework.
"Doesn't reinvent the wheel" they literally created a whole new language called JSX, I have 13 years writing JS and I dislike React and JSX is one of the reasons. As far I can tell reason it's picked a lot of times now it's market share, people see that is more popular than the competition so they try to learn it, creating a feedback loop that just makes it more popular.
I actually like JSX a lot, but I'm baffled when people act like the very thin DSL used by svelte is any more unapproachable than JSX, or like JSX is somehow more javascript when it's a mish-mash of extended HTML (don't forget to use key as needed, and className), React components, and JS (expressions only, not statements... and weird-looking ones at that)
JSX is a simple transformation of nested JavaScript functions, but the custom DSLs used by other frameworks is string templating, which is kind of an inversion of how JSX works. JSX also has extremely good support in just about every editor and it supports TypeScript, which is not true of every DSL.
I recoil from svelte and such because when I see someone trying to invent an ad hoc language inside html attributes I get flashbacks to "transcluding" "directives" of Angular 2.
> don't forget to use key as needed, and className
Those are part of React, not JSX itself. Compare Vue's use of JSX, for example, which just uses `class` and `for` instead of `className` and `htmlFor`.
False, for a lot of attributes you have to use the HTML naming of the attributes, so is not consistent, for example to use aria-label you have to write it exactly like that (not ariaLabel as when using JS)
JSX has been around for 7 or so years... that's a good amount of time. Over half of your 13 years :)
Do you avoid JSX when using Vue or other libraries that support JSX? Are you invoking the library function directly - React.createElement or vue's equivalent instead?
Yes I do, the only language I use for my personal projects is Typescript; I think JSX, .vue, .svelte they are all a mistake, JS is more than enough if you really need to use it to compose html.
div('#wrapper',
div('.container',
span('.big', `It's not that hard`),
button('.red', {route: home}, 'Home!')
)
)
If you look at library popularity more broadly, you’ll find over longer periods of time only those people enjoy working with actually continue to grow regardless of previous momentum. People really do move on if it doesn’t work well enough for them.
Take React form libraries for example [1], redux-form used to be the most popular by far, was followed up by react-final-form from the same authors so people naturally flocked to that. But that is now clearly seeing a decline as react-hook-form, a library that started from zero, is a lot more pleasant to use.
Call it what you want, still is the worst kind of syntatic sugar, the one that forces me to use a transpiler but its full of footguns, like being unable to use "class" for the "class" attribute and I have to use className instead, or the one that has no syntax sugar for conditionals so instead you write horrible stuff like {isValid && isApproved && foobar && <div>...}
If you're going to call something a footgun, make sure it's an actual footgun and not simply using a different naming convention than the one you want. You want the HTML name while React uses the Javascript name.
It is a foogun because is only for a few specificic attributes (class) that it uses this specific convention, for other attributes it uses the normal HTML attributes, for example in JavaScript to add aria labels you do stuff like "ariaLabel" when using react you have to write "aria-label" instead.
Vue is more akin to the old way of doing things with static templates (Jinja, Mustache, Erb, PHP), just with a dynamic twist.
React is not perfect, it's bloated, but the reason it took off is that it brought something new to the table as a general and programmatic way to construct UIs. Being a child of Facebook helped it achieve dominance but considering that before React we had angular (shudder) and jquery, React's success was well earned.
React will be replaced when something actually better comes along. The current contenders seem to want to return us to the technology of the past, it didn't work then and it doesn't work now.
Everyone is going back to "past technologies" like SSR, being old tech does not mean obsolete, send html directly to the browser in most cases is better than render them in the client, I think the better approach in theory is the island architecture that I saw on Fresh/deno and Qwik, both feels more like how we used to work in the past, minimal JS send to the client and more HTML send from the server.
SSR never faded and has always been an important requirement. Especially if you wrote SEO sensitive SPA's. We are not going back to SSR but are able to combine both SSR and SPA's more easily, as is indeed the case with dynamic islands and for instance React Server Components.
Not sure if you've worked with Vue 3's "composition API", but it is very different from Vue 2's "options API".
The composition API is bliss.
What's more important with Vue and fine-grained reactivity is that it is very forgiving of mistakes and poor practices that in React would cause much more significant side effects and performance issues.
Vue in general has been a godsend to me at least. When I was in college, we used AngularJS for web development courses at the time. My first job had me working with Qt and Tkinter. When I finally had the chance to do web development again, my team chose Vue and it was so easy to pick up from my AngularJS background.
My current team is using Vue 3 with the Composition API and it is way more forgiving with mistakes than the Options API. I've helped transition 3 developers so far to Vue 3 and they all love what Vue has to offer when compared to React.
React isn’t moving fast. React server components were announced two years ago and are still not available.
That said, as a low-level library it should not move fast; it should make sound design decisions while maintaining compatibility. It’s completely open to frameworks with more opinions and friendlier DX to be built on top of it.
>Functional components and hooks were a huge innovation to class components and significantly improved the ergonomics of the library.
I see this said a lot with particular regard to hooks, and to this day I just can't buy in.
For whatever problems class components have, they enforce a general layout of the component in a way that hooks don't. Reading some codebases that are all in on hooks feels like the wild west and is frankly nightmare-ish to untangle.
Are you saying that React is bad because a Junior Developer cannot bother to think about caching or at least open introductory materials before using a framework? If that's the kind of problems you deal with, that makes React one of the greatest framework ever.
The purpose of a good framework is to make developers productive, regardless of their level of expertise.
A junior dev isn't going to be build as fast or as clean as a more experienced dev, but a good framework promotes speed and provides guardrails to prevent mistakes.
To that end my experience with React -- same as the author's -- is that React does not have this characteristic and provides many ways to shoot yourself in the foot.
It's more like React is the MFC to HTML5's Win32. A not very good API with a near monopoly that people spend lots of time wallpapering over with ever more elaborate frameworks that end up being used only for distribution reasons.
Admittedly I haven't worked on a large multi team react project before but I thought the whole point was that Facebook found React scaled well with teams (vs the state of the art at the time)
Not only can you componentise your UI code, but you can componentise your UI system meaning teams can develop independently of each other...
That's not what I see and hear though. People complain often about how complex things become with React and simple things take a long time to set up or develop, compared to rendering a simple template on the server side.
Usually people are not FB and people often do not have the same kind of strict development rules or enforced discipline, nor are they as many people as FB. Maybe the FB tool is not right for them.
Where React usually gets complicated is when non-trivial state gets involved.
Once you have state that needs to span your application and prop-drilling becomes too much of a drag, the misalignment between React's "pretend we're going to redraw everything" and "I'm only changing this one field in my state" causes most of the issues with React.
Calling React the next IBM is giving React way more credit than it's worth. Sure, basic knowledge of React will land you a frontend dev job pretty much anywhere in the world. However most of that work will be maintenance. If anything React is the new PHP.
Things get more complicated when you start using React Context and start signalling updates in a parent component. The render cascades. Maybe one component fetches some data, some component remounts, and you run your state update again, delayed by a few seconds.
I'm not sure I'd ever expect a framework, React or anything else, to stop that behavior. If a child component signals to a parent that the state has changed then I would always expect that to cascade down the node tree. That could cause further updates. And more renders. That behavior is on me. If the framework decided not to cascade some updates that would be weird.
I think this highlights part of the problem with React and most other frameworks - people expect too much from them. If you're delegating all of your coding skill to the framework and expecting it to just magically work no matter what dodgy code design you throw at it then you're going to build a shitty app. You have to remember that you still have to think things through, use your skills as a dev, understand what's happening and why. That is always going to be true. You're always going to have to put the work in.
At the beginning of the article the author says they feel trapped by React because their previous, current, and next jobs are all going to be React based. That isn't true if they choose to put effort into learning other technologies and seeking roles that use them. If you work hard you find options open to you. Heck, they could move out of web and start writing completely different code that isn't even JS if they felt they wanted to. No one is being held hostage by React. You are only held hostage by your own fear of doing something hard. Feeling like you have to stick with React is a state of mind - you can change that with enough effort.
> I'm not sure I'd ever expect a framework, React or anything else, to stop that behavior. If a child component signals to a parent that the state has changed then I would always expect that to cascade down the node tree. That could cause further updates. And more renders. That behavior is on me. If the framework decided not to cascade some updates that would be weird.
It's not that the properties shouldn't be updated it's that in React the whole subtree gets completely re-rendered, with a potentially big performance cost. Svelte just changes the relevant bit of the DOM, like a single class attribute or whatever, and leaves everything else be, this feature alone is what made me switch. In addition to baseline performance benefits certain things which are really awkward in React (e.g. animated transitions) become non-issues.
>Feeling like you have to stick with React is a state of mind - you can change that with enough effort.
I really appreciate your optimism about switching to a different framework/ etc. and I would have felt the same earlier in my career where I didn't have so many non work commitments, financial and otherwise. But to me now this reads as wishful thinking; switching track is difficult, especially when your existing skill set represents a large chunk of the demand in the marketplace. (And I say this having recently sucessfully made the switch from React to Svelte)
I really appreciate your optimism about switching to a different framework/ etc. and I would have felt the same earlier in my career where I didn't have so many non work commitments, financial and otherwise. But to me now this reads as wishful thinking; switching track is difficult, especially when your existing skill set represents a large chunk of the demand in the marketplace. (And I say this having recently sucessfully made the switch from React to Svelte)
No doubt there are individuals with circumstances that make switching tech stack harder due to the demands on their time elsewhere, and I feel for those devs being stuck on a stack they don't enjoy (I was a PHP dev for a decade, I understand their pain). But I also think that those problems are temporary. You might be stuck on something for a few years, but in the grand plan that is your career spending even a couple of hours a week to move to something that you don't hate is worthwhile.
It'd be awesome if everyone who dislikes React could spend a month immediately learning Svelte or Solid, or Kotlin or Swift, but that's obviously not possible. All I'm saying is that if you're not doing anything to change your future then you should seriously consider if the problem is as bad as you might say it is.
> switching track is difficult [...] (And I say this having recently sucessfully made the switch from React to Svelte)
Having developed with Angular and React, and dabbling with Vue, I have to say that Svelte has the best ergonomics of the lot, and the language tutorial is so approachable. I haven't had to think about performance or state to the degree that I have in other frameworks. Any workplace could easily skill up a Svelte dev from a React dev.
Yeah, but atleast in Svelte it's explicit, and you can if you wish write svelte as if ste were immutable. Anecdotal, but still, I've had fewer bugs (particularly wierd UI glitches) in Svelte than I ever did in React. I just like Svelte for the types of project I work on.
Tangent: the idea that "we all agreed to say no thanks to that" is kind of symptomatic of broader issues I have with web dev. i.e. that there's very little recognition that different tools have different uses and knowing when to pick which is part of the job. Working with wood you wouldn't apply the same practices and methods to building the timber frame of 2 story house as you would to making an intricately carved toy elephant. Why when working with the materials of the web, HTML/CSS/JS, do we assume there's a best and right why to do it: "you must write tests!", "avoid using z-index!", "separate content and form", "immutable state!"; these are all the right answer in some situation and not in others.
> I'm not sure I'd ever expect a framework, React or anything else, to stop that behavior.
Isn't this the whole selling point of Solid's signals? If a child component receives its props from the parent as signals, and asks the parent to fetch some data and update the state, then the child won't rerender; only the bits that are consuming the signals will. Fine-grained reactivity, they call it.
I've not used Solid much so I can't say, but my point is that if your app is rerendering unexpectedly that's because you haven't spend the time to think about the data flow around your app. It's possible, and not that hard even in a large app, to build things so that this doesn't happen. Signals sound like a way of avoiding updates, and if the experience of using them is elegant or if the performance is better that's awesome, but you definitely can build apps without them and never see the problem they solve.
> If you're delegating all of your coding skill to the framework and expecting it to just magically work no matter what dodgy code design you throw at it then you're going to build a shitty app.
Not to disagreed with you here, but there are many frameworks out there which either claiming themselves as "full-stack" or trying to be as full-stack as possible.
The developers who uses these frameworks might just expect "(delegating your code to the framework) is how it suppose to be used"(, while blaming people who write "raw" JavaScript code as "hacky").
This is a problem which will occur whenever you want to standardize the workflow as well as the knowledge base for your team. Some approach is discarded in this process and what's left in the end are often "common practices" which nobody has reason to reject. If the "common practices" is to let the framework to do it, then that will be that.
I've been working on a React side project for a few months now and looking at my company's apps plus posts like this I think people just miss the point. Stuff like this:
>Things get more complicated when you start using React Context and start signalling updates in a parent component. The render cascades. Maybe one component fetches some data, some component remounts, and you run your state update again, delayed by a few seconds.
This is just doing it wrong. State should change in response to user inputs. Ultimately, React is f(newState) => UI. If that function isn't pure you're gonna have a bad time. It's hard to blame anyone though. The docs suck and most of the tutorials you find get it wrong one way or another.
That said, there's kind of a reason why functional programming isn't more popular. It can be hard to grok and there can be a significant performance overhead. There's also a reason why this sort of implicit programming isn't as popular as imperative style. It's hard to predict what the implicit behavior is and footguns abound.
I get so lost in these conversations, because I've been the lead on a relatively complex React app for literally years now and none of any of this has mattered or come up in any way whatsoever. Our app is plenty fast/responsive, maintenance hasn't been perfect but it's been manageable, same with new features... The learning curve around context was a bit steep but we get it now and haven't had any issues since.
It's like you're speaking a different language to me, and I find that so weird considering we're using the exact same framework. How am I not having any of these issues?
I'm honestly at the point where I wonder if y'all are making things harder on yourself somehow, because I could see how getting obsessed with counting every single re-render and trying to overoptimize would result in the stuff you're saying while not actually impacting perf in a meaningful way.
I've been in the same boat with these discussions.
When I do encounter a component with countless re-renders as described, it is usually painfully obvious what causes them and easy enough to fix.
I think we're going too far if we're expecting React, or any framework, to be fool-proof to the point that we can just throw "whatever" we want at them and expect it to have peak performance.
Depends on what kind of so your building. For a while, a lot of the form libraries out there triggered huge numbers of rerenders and caused perf issues. That's still a problem, though some of it has gotten better uncontrolled components.
Timing-based UIs are (such as a sequence of triggered animations) can get really messy really fast. I've seen some really messy bugs in a app that had visuals and audio tied to different timers and user inputs in the app. We eventually moved all time-based animations to observables, which helped some
Sure, but then you're managing state and re-renders yourself. Kinda defeats the purpose of using the framework, right? The useRef() approach to fixing performance is the main reason why I think Signals are popping off. Users of frameworks like Vue and Svelte have felt this way for a long time.
I've worked on a form + animations based site ~2 years ago. Forms via higher-order functions, it was a full-stack NextJS thing. Without TS.
I had to eventually claw my eyes out and that solved part of my problems, at least I did not see the boilerplate and the ugliness.
Then soon after that we worked on a similar thing (form + draggable carousel with snap to grid animation) in Angular with Material.
And my conclusion is that whichever framework you pick, whatever libraries you end up using, you must have a strategy to allocate your time and maintenance budget, and many many many times the sane compromise is to write something in raw JS and encapsulate that in whatever the framework gives you, and move on. Don't try to solve it within the framework, because it's just not worth it.
Forms were annoying but `react-hook-forms` eliminated any random issues we had, and now forms are fine. Again, context saves the day here by letting me grab the form context within nested components to keep everything humming.
I don't know if we have any "timing" based components, though we manage global state using Apollo Client and again, haven't really had any issues with that.
In my experience redux-toolkit + redux-saga for async stuff usually work really well. In case of performance problems one can go with profiling + targeted optimisations (e.g. a separate store, some locally managed state).
Glad to hear RTK is working well for you! FWIW, we actually specifically recommend _against_ using sagas in almost all cases. Instead, we recommend using our RTK Query API for data fetching and caching, and the RTK "listener" middleware for reactive logic:
Thanks, I wasn't aware RTK now has a saga-like "listener" feature - will look into it!
What I like about sagas are their simplicity & power (once one understands how generators & effects work), plus the eventChannel feature which lets one integrate with non-redux events. Good TypeScript support is a problem though, and I've had to resort to typed-redux-saga :/
Yeah, we specifically designed the listener middleware to do ~90% of what you could do in sagas, but with a smaller bundle size, simpler API, and better TS support:
Event channels was something we intentionally _didn't_ try to replicate per se, and tbh I've never tried to use those myself. (But, I _suspect_ that you might be able to do something similar with listeners even though we don't have a specific replacement built into the listener middleware, and if you do I'd love to see an example in action!)
If you get a chance to try out listeners in your project, I'd definitely appreciate feedback on how well they work out for you - whether they solve your current saga use cases, what cases they _don't_ handle, anything we can do to improve the listener API, etc.
I had to rescue a redux-saga project that went badly off the rails. It was one of the most inscrutable and difficult to debug codebases I've ever had to work with. Forget completely about ever having a usable stack trace.
This is why people use redux, keep state in a store and just do v=f(state).
Your app is the store, not the DOM.
It really makes things much simpler. The trick is to keep all the state in the store, including when things are loading, when some user interaction is happening but not yet complete, etc.
From your comment, it seems like there may be some problem if the user is interacting somehow, let's say in the middle of doing a drag and drop, and some data update comes in from a websocket, right? Well, if that's going to cause a problem for your render it's because apparently your data-updated function h needs to know if the user is doing a drag and drop. That should get put in the state when the user starts the interaction, and now h can know about it and react correctly.
Yes, it's more complicated than just have some component render based on the data you receive, but that's because it turned out that your app was more complex than you thought, it has more states you need to care about.
There's no magic wand, but this stuff works, just adds some boilerplate code but I don't mind.
>> I've been working on a React side project for a few months now and looking at my company's apps plus posts like this I think people just miss the point.
The clue is in if everyone is missing the point but you, may be start with more introspection. :)
I will give an example of a side project I am working on. The homepage has two sub components, one when the user is logged in, one when the user is logged out.
Now, when the user logs in, the state of the homepage parent component needs to change, the state of the nav bar needs to change etc.
Your problem is in assuming newState is completely described locally which isn't always the case.
GP's post reads like a definitive example of Dunning Kruger. These are large-scope issues that the article highlights likely won't be apparent in smaller efforts that could be referred to as a "side project".
You are both right. React components should render based on state that is managed by React, such that the
rendered output changes only if the state changes.
The complicated bit is the handling of events and changing the state. Hence why you get Redux for state but there is no “Redux for views”
React very heavily pushes "component lifecycle" events, since it was class based up until now with hooks. That is, changing the state in the view function itself.
It's not wrong, it gives you one kind of separation of concerns: components. But "the view is a function of state" is completely misleading IMO.
The linked article doesn’t convince me, instead it shows a misunderstanding of react and hooks.
> But then they added hooks and useState and useEffect and so on, which made the functions impure. The problem with hooks is that they “hook into” React state and lifecycle features, which means it is modifying global state.
React components don’t update the dom every time they run, they update the fiber tree / virtual DOM.
Only in the commit phase is the DOM updated and side-effects are run.
My rough understanding is that:
Hooks, excepting useEffect, all run in the render phase.
UseState hooks store data in the component in the fiber tree, and capture a sequential list of updates when you call setState.
Algebraic effects can seem a bit odd at first, but it’s really like a generalised try/catch. Instead of storing state in the function itself, you reach out up the stack to the component and store it there. And every hook you call from your hook stores it there too.
It’s why call order is important, because it’s how they know which is which.
You don’t modify any global state though.
The actual component function needs to be able to be called multiple times in the render phase (which just updates the vdom), and must have the same output each time, if the inputs/props are the same.
Every now and then, the tender phase can be interrupted to run the commit phase, which synchronously brakes a snapshot of the vdom and applies all the needed updates to the outside world.
I would absolutely say components and hooks are functional, with algebraic effects. And that the resulting data struct from those components, is what’s used to produce side effects.
Even useEffect, is a description of a side effect to run, it doesn’t run in your hook, it runs on commit with all the other side effects.
There’s a ton of optimisations under the hood but that’s roughly my understanding of how it works.
> ...and capture a sequential list of updates when you call setState.
In functional programming, functions are not allowed to do that. The only thing a function is allowed to do is return a value.
> ...you reach out up the stack to the component and store it there.
FP functions are not allowed to do that. In FP functions can only rely on the parameters passed to it (it cannot refer to anything outside) and it should not do anything beyond return a value.
> It’s why call order is important, because it’s how they know which is which
In FP, functions can be called in any order (unless one function needs the return value of another), and the final result is not affected by the order.
> You don’t modify any global state though.
If you have state it is not FP, whether it is global or not.
I find it's best (if side effects and state mutation make you nervous) to think of hooks as essentially part of the function signature of a react component, both on the parameter side, as well as on the return side. They are not written as such, because of syntactic limitations of JavaScript, but essentially a react component that starts off like this:
In this version, those hook functions are side-effect free, pure functions that our caller provides us with, closed over the previous stored state of our component in the tree; and when we return the results along with our rendered output, our caller has the new state of our component together with our desired DOM.
Instead of forcing us to write all that extra code, route those extra variables, and figure out the metadata mechanism whereby the caller of the render method figures out what hook functions to supply, the rules of hooks let you use JavaScript's imperative, procedural syntax to call hooks which are implemented using ugly side-effecting impure techniques, but in a way that pulls off something semantically identical to this pure functional flow.
Don't call this functional programming. If you call setCount() then this is not functional because your function is doing something besides returning a value. In fact, it is setting state, which is against FP principles.
Most of the ideas at play here come from the functional programming world, which is why it’s often viewed from that lense.
React builds on functional reactive programming, something the FP world is known for[0]. I’m not saying it’s pure FP in the dogmatic sense, I just wanted to point out it’s closer to FP than the other paradigms.
Without the ability to interact with the outside world (side-effects), FP is not of much practical use. Not to say it’s bad or shouldn’t exist, just we need to add to it a bit to make it useful.
Why would we do that? Because the underlying ideas and principles provide a great foundation. Building on that to get FRP and algebraic effects, monads and so on, is very different to starting from OOP and brining FP ideas over.
React hooks are an interesting and tricky thing to put in a box, because they’re almost monads, almost thunks, almost algebraic effects. The interplay with fibers and components makes them hard to pin down, but they are much closer to functional than any other paradigm.
The web is (was) a pretty good example of something akin to FP: REST means all state is transferred with the response and then the whole thing is rendered in the browser. And then there is HTTP, so if you want a new page, you simple call another URL (like a function call). OK this is glossing over some parts like that cookies are also send, but they are additional optional arguments of that request (function call). That's what the mean (or meant, since the term is now muddied), when they say the connection is stateless.
What we have with badly written React apps now (90% approx.) is a UI, that is not at all behaving like a typical website and very far from being like FP. We often cannot simply go back with the back button and expect to see the same page rendered. I mean we can, but the websites will fart in our face, if we do. We do not get the ability to simple send a link to someone and have them see the exact same page. It is a huge departure from anything FP.
Furthermore from the dev perspective components feel more mainstream OOP than FP, since they store internal state and update it, which indirectly causes things I described above.
Not sure where people see the FP. Not sure they really have done any FP language before or tried in projects to strictly adhere to FP principles, because that looks a lot differently than React components and mixing state, layout and styling in JSX/TSX.
> React hooks are an interesting and tricky thing to put in a box, because they’re almost monads, almost thunks, almost algebraic effects. The interplay with fibers and components makes them hard to pin down, but they are much closer to functional than any other paradigm.
They're almost classes (/objects). The implementation is what it'd look like if you wanted to make a weird half-assed OO... thing. Property and method declarations, getting attached (ultimately) to an object. But it's FIFO access/calling, rather than using named properties and methods w/ a lookup step. And the declaration syntax is bizarre and hard to read. And they're slower than regular JS OO (because they add an extra layer of JS on top of it).
Okay. But is it against FP principles to write software that runs in web browsers then?
Because web browsers exist, and they work in a nonfunctional way.
So to interact with one we need to do a little bit of imperative code.
And then react lets us figure out what to do when the web browser responds to that imperative code by letting us run a largely functional program.
Which is pretty neat considering we’re doing so in JavaScript.
The thing that we’re after here is not a badge that we can slap on our code saying ‘certified 100% functional’. We are trying to write code using patterns that help us reason about and structure what we want the computer to do, avoid bugs, and ship software.
If react managed to squeeze a surprisingly functional pattern into a JavaScript library to that end, can’t we just applaud the audacity and enjoy using it, without nitpicking that they didn’t actually reimplement the lambda calculus?
Why is it necessary to use FP to write software that runs in web browsers? To be sure, FP has benefits (such as, it is much more straightforward to reason about FP code), but those benefits are not applicable in React. So why pretend it is FP?
Web browsers are agnostic to the programming paradigms employed to code websites in. We might need to bend JS a lot to get FP though. JS has some quite procedural roots/basics. For example the timer API (setTimeout and so on).
I don't know react details but set<X> are not effecting directly, it's just another iteration from prev -> next state (with the values given in set<X> hooks) which is functional.
> In functional programming, functions are not allowed to do that. The only thing a function is allowed to do is return a value.
Oh, yes, they are allowed to do that. You capture the effects into a list, and return the tuple of list and return value. If you feel like it, you wrap that into a monad to pretend you are only "returning" a single thing.
> In FP functions can only rely on the parameters passed to it (it cannot refer to anything outside) and it should not do anything beyond return a value.
You mean explicit parameters (props) and implicit parameters (context), right? I thing you forgot the latter. Implicit parameters have existed for quite a bit, for example in the reader monad.
> In FP, functions can be called in any order (unless one function needs the return value of another), and the final result is not affected by the order.
Yup, except if you write a bunch of functions and store them in a list with the intention of applying the result of the first entry of the list against the first entry of the list. Now, if you construct the list of functions as effects (by hiding them behind a monad) you find out that you need to call the effects in the same order as to construct the list of effects in the same order. This doesn't contradict FP, it contradicts your mental model of how React is supposed to work.
> If you have state it is not FP, whether it is global or not.
The state resides in the runtime executor, exactly like Haskell's IO monad. Again, this contradicts your mental model, not React or FP.
Wow, I've never seen a reply that so thoroughly fails to address any of the points it's trying to reply to.
When you reply to "in FP, functions cannot do that (change state anywhere)", you say "you are allowed to do that: capture the effects into a list, return the tuple of list and return value" without realizing you're saying exactly the same thing?! The distinction between "return value" and "return value plus some other thing" does not exist. What matters is that the function's only observable modification is in what it returns, be it one value of many. This is basic FP.
You return a tuple, which first element is the value the function would return (I/E "return jsx stuff") and the second value is a list of operations (effects) you intend to perform I/E "I intend to change this variable to value X", "I intend to run this external function when these values change".
The function's only observable behavior is that it returns a tuple with JSX and some effect descriptors.
No, this is not basic FP. This is somewhat advanced FP.
I think you may be missing the forest for the trees. The point of FP is that you can glance at a function and say 'this is obviously correct' without having to work out the state and context of every call.
None of that is true in React hooks. The negative sentiment towards hooks that you see here is because it is weird and complicated. Want to see how much simpler code can get when you code without React or any such fat frameworks?
You just need to know JavaScript, HTML and CSS, not much else. The code is simple, and yet maintainable. No need for hooks, useEffect, useState, useMemo and all that crap.
How can you ever be sure that your state is valid when you’re putting it on the DOM? Worse yet, only parts of the state is stored there.
I can’t really call this code simple since it had to resort to timing hacks to get its functionality in order. A random 250ms delay and bam, bugs you cannot reliably reproduce
I'm not sure what timing hacks you're referring to - using setTimeout() with 0 delay? I think that's being done to defer execution of heavier functions and let other timeouts be handled first. Seems more like an optimisation rather than a hack to achieve basic functionality.
The first file I looked into was the combo box. This is what I consider to be a timing hack:
private onDropDownMouseOver(ev: MouseEvent): void {
if ((new Date()).getTime() < this.whenScrolled + 250) {
// We automatically get a hover event when we scroll, ignore it in order to keep our current highlight.
return;
}
const element = ev.target as HTMLElement;
if (element.classList.contains('combo-dropdown-item')) {
addClassExclusively(element, 'combo-highlighted');
}
}
Some event stores the time it has been fired, and this method checks that it has not been long since the firing. With react, which item has the highlight would have to explicitly be in the state and completely remove the need to do this optimization.
And this is an example of what I consider state being stored in the DOM:
The view has logic that depends on whether the dropdown is visible, which is checked by dropdown.style.display !== none. Now any element in your page has the power to modify this component’s logic by modifying the DOM
The timing hack is a workaround for a browser bug. The exact same hack would be required in React as well. What is this browser bug I speak of? Browsers send a spurious "hover" event when you stop scrolling, so that the item under mouse can be highlighted. This can cause problems in some cases.
> Now any element in your page has the power to modify this component’s logic by modifying the DOM
If some part of your application intentionally does something wrong, it can break your application whether it is React or some other tech. In this particular example, if you prefer, you can have a member variable to keep track of whether the dropdown is visible or not. Still no need for React.
As you can see, none of the complexity of React is necessary. No need for hooks, useEffect, useState, useMemo and all that crap.
Would it, though? Keyboard event sets highlighted item key/id; scroll event pops up, sets the highlighted item again, then react does not do an additional render because the state has not changed since the keyboard event.
The code does not have any complexities of hooks (which are just a javascript approximation of do notation, I don’t believe it is that complex), but what it does have is the requirement to write down all of your mutations correctly, where every “down” is an exact opposite of the “up” and does not leave any artifacts—with no way of formally checking. At least for myself, I think that level of discipline is unreasonably high so I tend to prefer stricter typed functional solutions where the view is composed purely from the state
We’re coming at this from different mental models.
The code you linked is what React helped me get away from. There’s multiple files in different folders for one screen. It’s hard to see how it composes, which is a useful boundary as it lets me know in the scope of that part of the UI.
UI is _hard_. There’s complexity that needs to go somewhere, and I’m one of those who prefer to push as much if it that isn’t business logic into a framework.
This becomes exponentially more important for every engineer you add. Go success is along these lines, with typically only one way to do things it’s much easier to share code.
From the code you linked, I could find my way around, but piecing it all together took a lot more work than any of the frameworks.
You mention only needing to know JS, HTML and CSS. But you missed that you still need to know how all that code is put together, what calls what. How it updates. React needs this too, the only difference with it being a framework is that knowledge transfers to a different project.
And to be clear, I’m not saying you need to use react or a framework—going your own way is often how amazing new things are found.
What I am saying is your attitude isn’t helping you here. React is still arguably the most used framework[0]. There’s a reason so many of us like using it and it’s what you described as “other crap”.
Frameworks help with collaboration, in the same way programming languages do. To do anything interesting with a general purpose language, you’re either going to use a framework, create a new one with good documentation and build a community of engineers around it, or build a halfbaked one that few people understand.
I’m open to other ways of doing things. It’s a good way to grow. I learnt SwiftUI a little while ago, and while I don’t use it regularly it improved my understanding of UI building. I learnt imperative UI API ages ago, and know for sure I want to avoid/contain that into a more manageable declarative approach.
It is idiomatic JavaScript. If you learned Java at the university you'll immediately be comfortable with the code. Now consider React with hooks. It is neither OOP nor functional and it looks alien to anyone who knows idiomatic Java or JavaScript. Would you recommend a youngster learning programming to learn React? I wouldn't, because it is so frankenstein. This article makes that point better than I can: https://medium.com/codex/can-we-all-just-admit-react-hooks-w...
JavaScript brings together so many paradigms, I can see strong cases for multiple different expressions of the language.
We didn’t have classes until ES6. And they’re not real classes, they still use prototypical inheritance under the hood.
If you want truly idiomatic JS, you shouldn’t be using classes. You should only be writing functions, and build your class-like objects with prototypes.
On a practical level, I absolutely recommend new engineers learn React. The job market is enormous, it’s a skill the market still rewards well.
And it’s a very productive framework. It rewards you for learning it, with better collaboration and velocity.
I would say the same for the other major view frameworks too, but React still has the biggest job market.
Until ES5, the industry thought JS was a Frankensteinesque monster.
Until maybe 5-7 years ago, anything that wasn’t OOP was considered a bit weird.
Calling any of these languages weird, is like policing English speech. We borrow so much from other languages that’s words have multiple meanings. Pronunciation follows contradictory rules, and regional dialects can be hilariously incompatible.
There’s a few languages closer to French, which has a strict control on what the French language is. For example, Go. There’s really only one paradigm them, only one way to do things.
Like it or not, pushing the boundaries of language design and framework design is how we improve as an industry.
You can’t not like a new thing because it’s weird at face value. You risk missing the forrest for some moss on a tree, and being left behind.
And sorry, that’s the same article this comment thread spawned from. I didn’t find it convincing at all, it’s let down by a lack of understanding in a few key areas.
I love how you do React. I mean, what's more react-y than blanking the page then appending HTML? I'm gonna call that Rejqueryact, because it's jQuery inside React.
I'm not seeing React being used, though, just TSX/JSX? All the view and state updating is being done manually, but it looks fairly well-organised. There are small optimisations like debouncing onInput with a timeout (avoiding rapid re-rendering/reacting to every character typed): https://github.com/wisercoder/eureka/blob/master/webapp/Clie...
Is this really much more complicated to implement than the equivalent implementation in React? (It's probably a bit more responsive, at least.)
I think they’re referring to how Reacts mental model is to wipe the page and rerender. The earliest versions basically did that, and then they started diffing and applying the diff.
They're referring to a specific bit of code in that Eureka repo that sets innerHtml = "" and then does .appendChild(). They just apparently didn't notice that the code doesn't use React at all (and is meant to demonstrate the use of vanilla modern JS without React).
No. The point of FP is "minimize state and effects so that the code is easier to understand", not "write it in FP style so that by magic is correct".
For exactly the same reason OO is "put the code that manages the state near to the state and split it in manageable parts" and not "dog inherits from animal therefore the code is correct".
Leave the faith at the church and approach code with science.
No matter how sophisticated the language we use to describe it: it’s still a bunch of side effects and state.
If you’re fetching some data in a useEffect you might not get a result that day.
If you’re updating something with setState, you are still managing state. UseState is a reference to a mutable object now.
You’re simply not getting the same answer every time your now impure function is called.
In order to do understand what’s happening you need to recreate the whole state. Which is exactly the same reason state management is hard as in OO or procedural.
You might have a mental model that explains why it is still FP, but for all practical purposes of that paradigm it isn’t.
But it’s a powerful escape hatch like rust’s `unsafe` block. Rust can do amazing things to ensure safety of your program, but there’s still times where a human can do it better.
By signposting that, keeping it to limited blocks, and wrapping it up in a safe function you get the capability to do hard things, while exposing a safer API.
useEffect is similar, it lets you write the imperative synchronisation logic. For example if you need to interact with a DOM element that only has an imperative API, someone needs to do the work somewhere to wrap it in a declarative one. You can do that in a component with a useEffect hook, and then expose a declarative API.
It's still using the useEffect hook, but just wrapped in a useFetch or something. So technically you're not building a UI without useEffect, just hiding it, no?
Because at some point your function call is manipulating registers on the CPU. If we go even further, the CPU needs to load its next instructions and then the data required.
Point being, we abstract and encapsulate complexity and provide a simpler API around it. It’s the only feasible way to manage the inherent complexity.
React builds up a virtual description of UI. react-dom and react native take that description and synchronise it to the UI layer.
If you need to do something extra, that they don’t handle like managing a map widget (ie mapbox) in React that only has an imperative API, it sure would be nice to do that yourself.
You can build a UI without useEffect. You can hide messy implementation details inside a well tested component, and contain where useEffect is being used.
And, you can understand how useEffect works so that you can use it without it having a negative effect on you.
It's just that "You can build a UI without useEffect."
and
"You can ... contain where useEffect is being used."
are not the same statement. Maybe I'm being pedantic, but when I read "build without X", I think there is some method that can be used to avoid X, not that I can hide away X.
They’re not the same statement. Both are correct. But as always, the nuance is critical.
All declarative code eventually runs something imperative.
And anything non-theoretical is going to have side effects somewhere.
Painting to a screen is a side effect.
Reading a file is a side effect.
Software gets messy when it intersects reality.
But, we can do quite a lot by staying in a theoretical realm. You can build a whole UI in the theoretical realm, where no side effects exist.
When you actually need to run it though, you drop out the the theoretical and into reality. Now there’s side effect’s everywhere.
So you contain them. Encapsulate those side effects into composable blocks. Test them extensively. Offload that work to someone who’s just focussed on managing them.
Updating the DOM is a side effect. Making a network request is a side effect.
Contain them, test them, and then you can stop thinking about them.
If someone else has done all the work to contain side effects, you can build a UI without them.
From what I've seen that's like saying you need to use salt to be a good cook while pouring a bucketful on a salad. Perhaps it's technically true but from what I've seen you can build pretty complex UI without useEffect if you follow the rules.
You have to use it, obviously, but it should be used for side effects primarily. A good indicator is if all the values in your dependency array are react props/state, you're doing it wrong.
I am not sure I am following. Say your homepage has a link to a page that shows the top scorers in a league. Where/when does the fetching of the top scorers happen ?
- (The view may change to indicate you're loading the top scorers, if you want, that's a different matter).
- Receive the data, the view changes to display the data
This is opposed to:
- Click the link to show top scorers
- View changes to show top scorers component. A component loads, or mounts, or inits, or does something which triggers a data fetch
- Receive the data, the view changes to display the data
Your app "knows" you need the data when the user clicks the link, no need to involve the view components into this.
This gives you the ability of adding a lot of complexity to how you fetch the data that is best handled outside a UI component (like caching, reusing it in other components, error handling, retrying, throtling, whatever), while saving you from a whole class of problems where a misunderstood component lifecycle has consequences for your data. Frameworks like React or Angular are going to try to help you by caching outputs, reusing components, dropping updates for the same frame, prerendering, preloading or anything really. If you fetch data when a component does any of that, suddenly you have to care about it and fully understand it. The abstraction leaked. If you treat the component as close to a pure function as you can, things become much simpler.
This applies to relatively big, relatively complicated apps, controlled by a single entity, where it pays off to prioritize simplicity.
> - how is the data fetch completion signalled to the component?
> - how is the data piped into the component?
Both have the same answer. When you fetch the data you put it in the state, and then you render your components based only on that state.
If we're talking React the state makes it into the component through the props (pure UI component) or, if using Redux or similar, some kind of hook that triggers a rerender when the store changes (useSelector? My React-Redux is a bit rusty).
The point is not to worry anymore about change detection and rendering, because the framework takes care of it by being either fast enough that it can run on every change, or smart enough that it can tell when it's not necessary to re-render (caching, change detection).
Of course, this setup with redux etc makes a lot of sense for bigger apps with lots of state coming from different sources. I don't have any specific example I can point to, but any redux implementation examples could help. I use NgRx with Angular, and the docs are OK at explaining the flow of data.
The example you highlighted as "doing it wrong" is pretty typical for an autosuggest component: Input updates trigger some request, which propagates to some list somewhere else in the dom. As it's loading, a spinner is shown, but when results are retrieved, they're updated again. Throw in apollo to the mix or some other request library, and context is used.
Absolutely not only to user inputs, but any kind of event: response, websockets, push notification, worker task finished... a million things beyond the basic "click".
> If that function isn't pure you're gonna have a bad time.
Hooks let you deal with "component lifecycles" which make that function not pure. Only the most basic toy react components are pure, everything is about side effects IN your views.
I never understood why React became so popular.
I thought it was a kind of mass hysteria. I was exposed to a broad range of front end frameworks early in my career (Backbone, SproutCore, JavaScriptMVC/CanJS, AngularJS), one of my colleagues was experimenting with Google's PolymerJS and recommended it. After trying it out, I was blown away by its elegance and simplicity. Yet somehow it never caught on. When React came out, people jumped on the bandwagon en mass; most of them had never even heard of Polymer.
React had some obvious red flags; it seemed unwise to re-render entire components each time and regenerate the DOM instead of trying to work with it; it's a hack. It's not difficult to think of scenarios were it fails; for example think of what happens to an element's scroll bar after it has been re-rendered from scratch; it resets... Yet people kept coming up with workaround after workaround to all these kinds of issues. If they had tried PolymerJS (which was going for a native Web Components approach and interfaced nicely with the DOM instead of bypassing it), they would have questioned React's merits. When the useEffects hook was introduced in React, to me, that was a vindication of Polymer's stance (which it had figured out years earlier) that you couldn't completely pretend that DOM elements don't exist, yet React's solution was not as elegant as Polymer's as it was tacked on as an afterthought rather than as a carefully thought out design decision.
Nowadays, with native Web Components (HTMLElement) in most browsers, I don't see why people would still start projects with React, especially given the massive number of dependencies it typically introduces and how often they keep changing stuff and breaking compatibility.
They promised a simple component library which would be the answer to our prayers. What we got instead is a 7 year religious pilgrimage which involved a million developers simultaneously trying to make sense of it; attempting to discover its true form by inventing abstraction upon abstraction and growing increasingly fanatical as it devolved into a wicked monstrosity which should have brought the wiser among us to our knees, begging for JQuery.
From the moment I understood the weakness of vanillaJS, it disgusted me. I craved the strength and certainty of unidirectional data flow. I aspired to the purity of Blessed Functional Programming. Your kind cling to fad frameworks and half-baked web components, as though they will not decay and fail you. One day the crude spaghetti code you call an "app" will wither, and you will beg my kind to save you. But I am already saved, for React is immortal...
Love to see the Polymer shoutout - Lit, the web component library produced by the Polymer Project, is still my favorite way to organize web components. Nice and simple, provides just enough tools to be useful but mostly stays out of your way, and mostly sticks close to the metal on native web components.
I’ve always thought React was some sort of mass hysteria as well.
> It's not difficult to think of scenarios were it fails; for example think of what happens to an element's scroll bar after it has been re-rendered from scratch; it resets...
To this day I can immediately tell that an app was made using React once the first focus/selection bug rears its ugly head.
I’ve tried Polymer and the web componens, and for a long time it had a really bad accessibility story, and even worse developer experience. It is just google using their size to force bad decisions on the web world again.
This post follows the current trend hyping up signals, but glosses over the complexity they bring.
We can agree that state management is complex, no matter how it’s done. If you disagree, cool go build a database.
Of all the complexities around state management, the one squarely placed at the top for me is: time.
State is a variable you care about, that will change over time.
Signals and Hooks/Effects present two very different approaches to the problem.
They both require updating your mental model, and they both have specialised tooling.
Myself, I’ve never fully grokked observables/signals—particularly in relation to a UI. They shift complexity into a location that I think makes them harder to reason about.
I did take to the React approach with Components and hooks. And in my experience so did many others.
I disagree with the article saying all frameworks must have signals, and I appreciate the React core team holding their ground on that.
It’s healthy for the ecosystem to have frameworks built on different ideas, otherwise why build a new framework?
But React, if you added signals I think you would warp it’s entire foundational paradigm.
I don't understand the animosity around useEffect. It executes a function based on a list of dependent variables. That's it. Once you understand that, its purpose becomes very clear.
You don't want to rerender? Use useEffect with an empty array! Or don't use any state variables!
You want to show something new to your customers / users without rerendering? Well sorry, that's impossible, regardless of any framework you use and you should go back to UI development 101.
Bottom line: if you write clean code and are aware exactly of what your local state / redux variables are (or whatever state management you are using), you should never have a problem with too many rerenders. I've been writing React for 6+ years now and have NEVER had to reach for useMemo or useCallback.
> You want to show something new to your customers / users without rerendering? Well sorry, that's impossible, regardless of any framework you use and you should
go back to UI development 101.
When you say “render” are you referring to what React means by “render”, that it will go through the whole virtual DOM cycle? Because it most certainly is possible to avoid that when using pure JavaScript. Why do you say it’s impossible? React’s fundamental problem with performance, and the whole reason people often don’t want to re-render is because React renders everything, then does a big diff on the DOM to compare it to what was rendered before, and then updates the elements that changed. I know a lot of work has been put into making that process fast, but it’s still really expensive compared to the pure JS way of doing it. In CS terminology, updating a button or any other single element went from an O(1) operation with JavaScript to an O(N) operation with React.
Not sure I understand your point, can you elaborate?
My point is that updating the state for a single element causes React to compute the state for the whole page, and diff the whole page virtual DOM against the whole page actual DOM, before pushing the update of that single element into the DOM. With pure JavaScript, you can skip all that and directly update a single element. This is often in practice much faster.
I agree, and I'd like an anti-hooks person to explain their thoughts a bit more. My impression is that they believe useEffect inclines devs to cause side-effects in the component, quickly making the logic of a component difficult to follow- for example, a useEffect that sets a state that kicks off another useEffect that sets another state that kicks off another useEffect...
But this problem existed before hooks: old school React devs will remember the days of class-based components with humongous componentDidUpdate methods peppered with calls to this.setState(...) that did the same thing.
My own impression is that hooks offer better lifecycle controls overall, with the side effect (heh..) of handing devs an arsenal of footguns that will inevitably go off if they don't fully understand the hooks or where to use them or how React detects and triggers a re-render. So in a way I agree with the author of the original article here, but in the sense that React devs should probably not use hooks until they understand how re-renders happen and why to avoid that and only then should they be handed one footgun at a time.
Trying to make state updates at the top level of a component will result in an infinite loop.
```
I've taught React to dozens of people without ever seeing someone try this. A render function is an idempotent function that produces UI for a given state, and it's called every time the state changes. What are you, semantically, trying to do by updating state midway through a render function? This isn't a footgun, this is the author picking up a screwdriver and going "I wonder what happens if I press it against my eyeball"
That’s a good point, that example does feel a bit contrived. Interestingly though it is actually “canon” to call setState within the render function (for certain rare situations). I didn’t actually know this until I read the React beta docs: https://beta.reactjs.org/learn/you-might-not-need-an-effect#...
Most people who use React don't understand idempotency, in my experience. Without understanding that fundamental concept, and that that React will blow away the tree and recreate it (albeit efficiently), one will not understand React.
I like the mental picture of the comparison. Consider, that you might have taught a boased selection of people, and that others might not be so diligent to have read the docs and actually thought about it in depth to also understand it ; )
The idea of pure functions deriving UI from state is the single central idea of React's worldview. The docs work extra hard to get this model of apps into your brain. This is not the same thing as people being elitist about Git, this is refusing to engage with the design of the framework and blaming the framework.
I like how you say "others might not be so diligent to have read the docs"... As opposed to? Picking up a UI framework and just winging your way through LSP autocompletions until something happens on your screen?
I had a co-worker that assumed it worked template-style, where the value in the JSX would update and what's on the page would re-render, but the component function wouldn't be re-run.
It's exciting & unsurprising to me that state is such an unsolved problem.
For the longest time React was kind of in denial to a large degree about what they were. They called themselves a View library. Hooks have definitely noticeably changed that relationship, & how people integrate app state with React, but the problem here of updating hasn't really changed all that much.
It's not a new thing either. A lot of the initial resistance to React & the VDOM was that it felt like unnecessary work. Because so many frameworks at the time were working towards two-way data-binding systems, which aren't necessarily but were often associated with with smaller, precise DOM updates. HP/LG's WebOS's underlying Enyo project was one high profile would be effort here.
Signals have definitely been a good re-grouping point, for reconsidering what the shape of things might look like, for trying to do a better job.
I'm a bit surprised we're still operating so much at a library level regarding reactive systems/signals. JavaScript objects have quite a lot of flexibility already, and the addition of Proxies added a lot of capabilities. Faint/distanct memory, but I think Proxies were justification for killing Object.observe[1]: now users could do whatever they wanted, so we no longer needed a JS native way to see objects change. Yet, we're still very library based, rather than trying to make objects themselves better, more reactable.
There is context which wages a war against debugging and testing, for one thing.
React has no real answer to state going sideways.
Then there is controlled/uncontrolled component which is an example of structural instability (what looks like a tiny change to your boss is a bigger deal than it should be) unless you ride the crazy train and use “plain ordinary javascript” to build a parallel system to move (some of) the state around.
If you are having trouble testing context, you are _definitely_ doing context wrong.
To test the context itself: pass as children of the context components to render the context state.
To test the components within the context: create a context with mock functions/values.
React has no answer to state going sideways because React manages a tree of components, and you are not supposed to connect random branches of a tree. That would completely break the concept of tree, container/contained, and just convert everything into a graph, and graphs are much harder to deal with. BTW, HTML is a tree, not a graph.
Controlled vs uncontrolled and the boss demanding a tiny change is just another case of bosses not knowing about how it works the system and imagining things and then demanding reality to conform to their imagination. Not an issue with React.
That still means you have 3 different types of entities.
One where the event originates (knobs), one where it will gets translated into actual UX effects (DOM updates, API fetches, whatever, lets call these servos and gauges), and one place where the business logic lives that transforms between the low-voltage input signal and the high-voltage output driver power.
Without that transducer you have incompatible things.
Yes, many times this is a trivial thing, and that's usually when it can be done internally to the component.
That is one of the many partial answers that works some of the time but not all of the time.
For relatively simple applications you can push all the state high up to the root of the tree or near the root of the tree and have it flow down with props.
There is a complexity hierarchy and around the time people woke up to AJAX (there were a few years when it was just a ‘evil Microsoft thing’) I was writing apps that were highly dynamic, the extreme example is an IDE with property sheets or something like Adobe Photoshop where an arbitrary number of components need to ‘react’ when a piece of data changes. It is bad enough when there is a status bar and four other parts of the UI determined by management that need to be updated when a piece of data changes (could become five or six tomorrow). it is worse when the user can instantiate arbitrary components (say for a knowledge graph editor or a geospatial intelligence tool) that ‘listen’ to event changes.
Prior to 2010 I was building apps like that and developing special purpose frameworks to do exactly as you say in GWT, Silverlight and such. There was no support for such things at the time, no async/await, management and other devs had no idea of the ‘race conditions’ that could happen when data could either come out of a cached copy or get fetched.
In those cases I spent a while struggling to understand the problem and developed systems for handling state in complex applications so when I look at React, Vue and most of those (with the possible exception of MobX) I want to ask “where’s the beef?” because these frameworks are not adequate to the problem and people don’t seem to understand they are no adequate to the problem (it comes from Facebook, how bad can it be?)
Most of the reason why people think "React is OK" is that they are writing apps (99% of them) that are so simple they don't need React. If you're writing apps that really need React, than React doesn't seem OK.
> it is worse when the user can instantiate arbitrary components (say for a knowledge graph editor or a geospatial intelligence tool) that ‘listen’ to event changes.
Your application is effectively "anything can modify anything", which is the previous step to "anything modifies anything", I/E big ball of mud. React's answer to that is "keep all the state in a small component" (small ball of mud) or "keep the state in a tree" (one-direction bindings, prevent state graphs).
This makes React discourage (I/E makes harder and puts friction) graph-based state, as it is the most direct path to big ball of mud.
This doesn't solve your problem, but definitely helps push 99% applications away from the big ball of mud. The fact is that for your 1% case you need the big ball of mud, and, in your case, pushing away from it doesn't help.
In those two applications I joined failing projects that really were a "big ball of mud" and got them working. I didn't just figure out a working solution to the async updating problem, I became intimately familiar with seductive non-solutions.
The problem with the discussion about React is that 99% of the use cases of React don't need to be an SPA. If it's possible to SSR your application you don't need React! Those applications I worked on were dramatically more complex than today's SPA because they needed to be SPAs!
Back in the 1990s people would define a web form in a static HTML page and then write a separate CGI script to handle the form. If there was an error in handling the form the CGI script was unable to redraw the form with an error message and the values filled in because the CGI script didn't contain the form.
Around 2000 or so people realized the answer to this was for the form to drawn by the same script as the form handler, and the script would choose to either draw the form or the next thing after the form based on the inputs it received. Ruby on Rails institutionalized this around 2005 and misappropriated the name "model-view-controller" for this.
Not long after 2010, for reasons I still don't entirely understand, the web design shops in my county transitioned from successfully writing quality RoR apps to attempting to write "simple" Angular apps. How to do error handling for forms on the server side got forgotten like the formula for Damascus steel and instead people started writing SPAs to do what would have been a trivial task in a server-side application except now the application is "a tiny pebble orbiting a supermassive black hole made out of dark matter".
People who are happy with today's SPA frameworks are happy because they are developing applications that don't need to be an SPA. Once you get into the range of applications that really need an SPA they let you down.
SPAs exist because of the developer experience and user experience, the support for complexity is an added bonus.
Everything can be done with SSR, but some things are terrible with SSR (oh, you need real-time updates? have some meta http-equiv refresh header, and observe the beauty of the page going blank and re-rendering every second).
Before you ask about the developer experience: it's about having developers that can focus their brainpower into animations and interaction design without having the expectations of having to know SQL.
Or look at https://www.phoenixframework.org/ to see what a web framework would look like if real-time updates mattered. (That said I do find that simple IoT applications like a volume knob for my smart speakers in party mode or that can toggle my lights do work well with websockets + mobx + React.)
As for DX, I think waiting for "npm run start" to get out it's own way is a large enough decrement that I don't have to get into all the many problems w/ JS build systems.
I will grant that React is nice for an animation-heavy UI and I play video games enough that I appreciate such things. Another thing I like about React vs similar competitors is that the rendering model is flexible enough to enable things like react-three-fibers which is another reason for me not to invest in Vue, Svelte and things like that.
As for user experience isn't it the dark truth that Google and Facebook want "as many UI redraws as possible?" Let's face it, the honest clickthrough rate on ads is indistinguishable from zero but when you visit some site like anandtech it is by no means accidental that the layout rerenders endlessly because each rerender is a chance that a click on a link is transmogrified into a click on an ad. It's covert click fraud and is a large enough decrement and between that and the endless staring at spinners and waiting things to load any possible increment in user experience is at best hypothetical.
(e.g. in another window I have a completely SSRed app that uses HTMX. It uses zero spinners, runs as fast or faster than a desktop app, and never has the UI move around mindlessly. I grant it would be cool if it had some more animation but would I trade that for rock solid responsiveness?)
HTMX definitely chips at some of the use cases of SPAs. What percent of cases? I don't have that answer.
And yes, Phoenix is a very interesting thing, but it's most likely only viable because of it being Erlang under the hood (needs a process running for each client, hence ultra cheap Erlang processes being a good fit).
> when you visit some site like anandtech it is by no means accidental that the layout rerenders endlessly because each rerender is a chance that a click on a link is transmogrified into a click on an ad
I think you went a bit too far into the conspiracy theory there. An element for which the height is not defined (via HTML or CSS) gets rendered usually to 1x1 pixel, which forces a redraw if the element turns out later to have width and height (like an image that takes half of a second to download). Which, IMO, means web developers are not bothering to put sizes in delayed-loading elements, which points a bit more to the incompetence side than the malice side. But ads probably not specifying width and height would also indicate significant malice, can't rule that out.
the "MVC" nomenclature came from traditional desktop apps, no? RoR just followed suit.
So, I always "hated" RoR, because it was full of hidden conventions and regular black magic. At least PHP was globally simple and primitive, even if locally ugly and complex.
I still remember Misko's early(est?) Angular announcement video, it was just part of GTAC [google test automation conference], and the whole thing was about testability.
It was seen as natural separation of concerns, it was seen as - finally - breaking free of the big bulky backend (of GWT and the shackles of semi-autogenerated frontend code) the frontend runs on the browser anyway, it needs to manage its own state anyway, etc, etc.
Of course this only emphasizes your point, that a good ~95% of the sites are not like this, they shouldn't even try to manage state on the frontend.
> Once you get into the range of applications that really need an SPA they let you down.
One of the main reasons I was so hopeful for Object.observe was because it would have been a stable language feature to build better debuggers around.
Instead, it feels like most state management libraries ultimately end of writing their own Chrome extensions. Which now that I say that makes me curious: do any of these executions also let you observe/monitor server-side state management systems?
You can often use route params or location hash for communicating state sideways if shared context is overkill, with the benefit of making the state bookmarkable or accessible in the history.
Right, the problem with React is it has no global answer for application state, instead it provides a toolbox with which it is possible to set up your own state handling but frequently you face structural instability where a small change in your app’s functionality require large architectural changes.
> or some mechanism to exchange that small piece of state for a more complete piece of state
using links to refer to information is, like, not a totally foreign concept to the web (and certainly granted: in some cases this issue of signaling via url can get quite ugly; but often it's not).
I can't help but sigh exhaustedly. There was a moment in time angular was the thing. And then x. And another. And React.
The problem each of them tried to solve, and continue to try to solve is purely lexical in the end. It's about writing things differently. Creating abstractions (terms) beyond what the underlying language/platform allows you to do.
And this is not a bad thing. The solution really is to create your own language so you can express the problem you are solving in the terms of the problem and not the underlying language/platform/hardware.
And then I sigh again... aah but if only Common Lisp and it's macros were the underlying platform.
> The solution really is to create your own language so you can express the problem you are solving in the terms of the problem and not the underlying language/platform/hardware.
That's what Elm is about. I've talked about it in another thread, so I won't repeat myself here.
I had heard of it, but never checked until you mentioned it in this context. It seems that Elm is an entirely new language written atop JS (or maybe not, and targets JS?). A DSL.
DSLs also usually are an incomplete solution. Unless they themselves allow adhoc language creation using the DSL as a base. Common Lisp with its macros allows writing DSLs quite off-handedly as you program. You grow your program and language together as you get deeper into your problem.
As a more backend guy who does some frontend, the main thing I like about React over alternatives like Svelte, Vue and SolidJS is React Native. React is maybe not perfect for the web, but it’s very, very good, and it’s also quite good for mobile via React Native. The more purely web-focused libs/frameworks have far inferior (or no) mobile options, while other cross-platform frameworks, like Flutter, suck on the web.
Being able to use such similar concepts/knowledge for both web and mobile, with strong results in both places, that’s something React is uniquely good at (AFAIK), and a huge reason to choose it IMO.
People seem to say Quasar [0] (a framework on top of Vue, websites, PWAs, mobile, desktop) is great in that niche, but I can only say that their documentation looks good.
Interesting, have never played around with it. Is it just a WebView on mobile, though? What I like about React/React Native is that it’s web-native components on the web, mobile-native components on mobile, so you get true native look/feel/behaviour in both places. Too many of the alternatives are WebViews on mobile, basically just a web page embedded in an app. Or they do crazy things on the web, like Flutter turning your webpage into a giant canvas. React/React Native is the only popular/mature approach I’ve seen that embraces native components on both the web and mobile, though maybe there are others?
Checked, yeah. Using Cordova or Capacitor. They say it looks native, though? No idea.
> What I like about React/React Native is that it’s web-native components on the web, mobile-native components on mobile, so you get true native look/feel/behaviour in both places.
Oh, that is cool. I never worked with anything mobile, so I didn’t know. I will read into that, not that I plan to use it, but it sounds interesting :D
I'm using React Native to build mobile games, and I am pleasantly surprised I can just write my own state management and update logic (hack around states and props) to walk around a lot of issues and get good performance.
Those same workarounds could be still be multi-platform (Android and iOS) and if you’ve got any sort of complexity in your business logic you don’t need to implement and test it in JS/TS + Swift + Kotlin, just JS/TS
Ionic gives you a solid base for mobile and the web with a slight bias towards mobile. It's all web components, no native renderers, but quite polished, because it's been around for a while. Imho, you can get quite far with it.
Is React good on mobile or does it just have a good solution there? I don’t think anything is stopping vue-native from popping up other than interest and someone to work on it.
But React/React Native is the only mature/popular web/mobile approach I’ve seen that embraces web components on the web AND mobile components on mobile, which I think is a big advantage. Though maybe there are others I’m unaware of!
I’m sure there could be React Native like solutions for other libs/frameworks, but I haven’t seen any that are as mature with the same “native components under the hood” approach.
Yeah, if you have a big team, everyone is going to be specialized anyways. You can have:
- Dedicated Android devs working on your Java/Kotlin/whatever Android app
- Dedicated iOS devs working on your Swift/Objective-C/whatever iOS app
- Dedicated web devs working on your JS/TS/whatever web app
- Dedicated BE devs working on your BE services, in 1-many languages that may be none of the above
But for startups, that’s not gonna happen, there’s gonna be wayyyy fewer devs and wayyyy less specialization. A lot of companies will be in that mode for many years, possibly indefinitely. In those situations, React Native can be a big win. I’ve been working the past 2 years at a relatively small startup, ~10 devs, that’s TypeScript everywhere. We’ve got 2 mobile apps (mobility space, a Rider and Driver app), both TypeScript/React Native/MobX. Rider is iOS/Android/web, Driver iOS/Android, very nice having 2 apps instead of 5. Then a web-only admin app in TS/React/MobX, and backend services in TS/Express. Same language everywhere, and similar mental model across all FEs, is a big productivity boon at our size.
There is this niche movement that argues that good code should be very long lived. It should solve problems in a fundamentally efficient way that makes it hard to turn into obsolete and throwaway code.
There are not many examples of such code bases. Maybe numerical algebra libraries come close.
Reading through the comments it seems that providing (fairly basic by now) UI functionality on cross-platform basis has not matured to the point of providing a stable paradigm.
Given how many people and for how long have been banging on this problem it feels a bit strange.
Surely people can find better use for their time and energy than churning through half-baked frameworks?
No, when you mention js libraries you are already starting the clock way too late.
The UI problem is not new. People were already building clunky UI cars long ago. MFC was introduced by Microsoft in 1992.
Of course the emergence of the web platform and mobile/touch devices complicates the matter as you now have a proliferation of platforms to address (desktop native, desktop web, mobile native, mobile web) but my argument is that fundamental patterns on how to do this efficiently should have emerged by now - and I see exactly the opposite.
It would be nice to see some sort of convergence. Reinventing the wheel might be "fun" or gainful in a narrow sense but it certainly doesn't help with productivity.
For what you're talking about, Computer Science History needs to be taught, which it is not, and if it did it would be filled with current industry trend propaganda. Fact of the matter, every developer have to learn it all themselves because this history is not taught. However, most developers get caught up in a "build now!, ship now! now! now! now!" and no history or accrued deep knowledge from other developers can be transferred with any quality or retention.
Never been close to one of these coveted Next machines but checking out what wikipedia writes about it [0] captures perfectly my point about good UI frameworks supporting productivity:
"1990 CERN: A Joint proposal for a hypertext system is presented to the management. Mike Sendall buys a NeXT cube for evaluation, and gives it to Tim Berners-Lee. Tim's prototype implementation on NeXTStep is made in the space of a few months, thanks to the qualities of the NeXTStep software development system."
> When I build libraries for React, ironically, I don't really use hooks like useState, useReducer, etc. One of the best perks (and footguns) of managing your state outside of react is that you get to have full control over when a component should rerender.
I don't understand this quote from Tanner. Aren't React hooks, like, the only way to tell a function React component (while inside of it) to re-render? And if you look at the code of, say, the useBaseQuery hook of tanstack-query, you will indeed find React's native hooks being used there [0].
I really only have familiarity with React-query, but I'd guess it's something like:
While of course React-query plugs into the React lifecycle, it's also kind of an escape hatch that plays nice with React.
Managing the fetch function calls, their state, their resolutions, and the cache, all probably happens outside of React, but then changes to any of the query state are reflected into the React lifecycle.
This probably lets him do something like using localstorage for storing cached query data, communicating between tabs, etc
I used Angular pretty heavily before switching to React.
At the end of the day, they approach the problem from two different directions, solve issues in two different ways, and end up with two different sets of challenges in terms of what's easy and what's hard in them.
I've definitely written React UIs that would be easier in Angular. But I've also crashed Angular performance through the floor trying to wire up a table display with Angular update hooks. Angular makes it easier to hide state-update dependencies in a way that causes really bad thrashing to reach steady state, which I've (anecdotally, generally) found harder to do in React because doing it in React involves writing a lot more code and a lot more cross-state dependencies.
What a nice idea it was to scroll immediately and figure out this is another bullshit reactive programming evangelism blogpost. Bro, we've already had this shit in JS like 20 years ago (Flapjax anyone?). Now go on and write your code like this for at least few weeks and see how great and maintainable and "fine-grained" it becomes.
Meh. The most important thing about React is you have to think like React wants you to. It's a very pattern-oriented type of development I haven't seen much of elsewhere.
Most of the footguns listed in this article are things you obviously shouldn't want to do because they're not React-y.
If it's not batteries included if should not require people to add a huge amount of overhead to their projects to use it, stuff like JSX or create-react-app
That's neither required, nor being recommended by the wider community anymore.
> JSX
JSX on the other hand I feel like is something that is essential to React (yes, I know that some people disagree), and one of the few things it should provide/require, as it forms a cornerstone of it's UX. Getting things set up to understand JSX/TSX has been smoothed out a lot now, and hasn't been an issue in any greenfield project I have set up in the last 2-3 years.
It's reasonable to highlight issues without presenting alternatives. If a valid alternative existed, people would have moved already and this type of post wouldn't exist.
You all will hate this: I've been a pro coder for 44 years, at a high level. I was an early Assembly programmer on the pre-release Mac in '83, a 3D graphics researcher during most of the 80's, OS developer for 3D0 & the first PlayStation, and quite a bit more. I have over 40 high profile commercial applications published.
I think React creates needless complexity. The software I write is complex by it's nature, I do not need the software I create my application within to exponentially increase that complexity. React does not just let one write code and create one's application, React dictates how the code is written, and if that does not fit with one's application structure you must change it. And React developers cannot wrap their heads around anything other than React's dictated way to write React, so... they are useless.
So, what do I use: nothing. I just write html/css with direct DOM access via js, very minimally. Dicking around with the web page is the least priority of the applications I write, and the freedom to create the application structure as the purpose of the application dictates is far more important to my clients. Plus, I do not write consumer click bait vehicle software, I write software for people to accomplish things, typically complex things of the nature an engineer, designer, or architect would use.
I missed it in the article. How do signals fix react's shortcomings? With signals you still have the same exact state management problem of having these crazy stateful functions. Sure you don't need to deal with the additional complexity brought about by use effect and rerenders but that's only a small part of the problem in my opinion.
I've gotten to the point where I think frontend code should just be modeled as state machines from the start. I like XState but you can use reducers too if you like.
I was super interested in hooks when they first came out. But after a short honeymoon period I noticed all the complex rules, exceptions, caveats, and footguns, and I wondered how the React team ever thought this was something you could put into the hands on new developers and expect them to not run into trouble.
It reminds me of teachers who have been teaching so long that they don't understand what it's like to be new to the subject any more. It's called The Curse of Knowledge cognitive bias: https://en.wikipedia.org/wiki/Curse_of_knowledge
Not to start an unholy flame war, but if you were to start a new project and didn’t need to worry about the ecosystem or workforce, what framework would you choose? Vue? Svelte? Something else?
I don't know about Vue3 (I used in the past Vue2 only), but Svelte is similar to React, I'm migrating a small/medium project from React to Svelte and it feels too easy most of the time to port component by component, also to me, at least to this point, Svelte feels more performant and you have 100% control over the reactivity without too much `use{function}`.
I would recommend you to build a small project, maybe a Todo app in every framework you want to try, or maybe if you have a project, build a small part of it in each (I will pick the part that you think is the trickiest to build with React or the framework you are actually using).
Also I'll recommend to also check Qwik and Fresh(deno).
I'm interested in what's happening in the MPA space. The Page and View Transitions API that the chrome team is working on, partial update libraries like htmx and unpoly, etc. If payloads are tight and servers snappy, many of the concerns that led to complex SPA architectures in the first place have begun to wither away.
Hotwire and Stimulus are great. They’re widely used within the league of “sprinkles” libraries and it’s well maintained. You can use it with any backend framework. I use it with Laravel and it’s a pleasure to work with. But it’s not trendy or fashionable, so expect a lot of looking down at you for using it.
Stimulus and Hotwire (on top of Laravel or any other decent batteries included framework).
Not a single one of the many projects I’ve worked on in the last 10 years needed such a level of interactivity that it justified the trade offs of using react or any other frontend-heavy frameworks.
I’ve seen entire CRUD spas that would have been built in 20% the time if we didn’t have to build a graphql api, figure outs authentication and permissions, integrate that with a custom validation setup, integrate all of the above with the translations systems, coordinate deploys or do forward compatible migrations, etc, etc. so much energy (and money) wasted.
But I'm also interested in trying Solid.js and Vue, and for some types of projects I'd likely even go Astro+Svelte or Astro+React.
Hard to speak authoritatively on the matter though because over my career I've only done vanilla JS, jQuery, Backbone.js, React, and then Svelte, in that order, and each has felt like a leap forward in evolution
Honestly just use what you know. Unless your goal with the project is to learn new things or to have fun, than go with what is most interesting for you. Or if you are in a larger team, then talk to your teammates and try to get a consensus around what you are most comfortable with collectively.
I only advice against using a niche framework if you suspect the project is gonna be long-lived and managed by a medium to a large team, in that case pick the one of the big ones—React, Angular, Vue, or Svelte—which your teammates can agree with.
I just started one small project that is a single component that talks to our API and is rendered on an external website. I used lit-html for it. Very small, very fast library for this kind of thing. No build tool required. I choose my own (smaller, simpler, more straightforward) way of managing state.
Be careful on spreading the statement "easy for React users", yes that's true for using JSX, but for React developers trying out SolidJS, make sure not to desctructure props, get rid of rerending function mental model, components only runs ONCE so reactivity works by tracking reactive elements(signals/stores) inside JSX or effects(createEffect, createMemo ect), that means no early returns. If a React developer (I've witnessed this with Twitch streamers), jumps into SolidJS blind without taking tutorial, they get lost into rerender mental model.
In case you're feeling alone. I detest hooks and I'm glad I was able to get out of front-end dev before they became wide-spread. I loved react at first with class components and its friendly lifecycle. It was designed to be understandable and self-documenting. It was a pleasure to write self-contained components. The move to function components, redux, and hooks stripped all of that away.
I'm glad others have found value in the evolution of react, but it always felt like watching a tragedy from the outside as the newest Abramov idea seeped through the ecosystem.
You say you detest hooks, but didn't elaborate why. Can you explain more? Is it just a preference for the class-based model of overriding lifecycle methods?
I don't know about the GP, but hooks are fundamentally an attempt to stick a state managing effects system into a language that is designed to use objects to manage state. This gives you something approximating the worst of both worlds - your 'functional' components are not pure, and the effect management system is something you have to deeply understand to use correctly, but it clashes with the rest of the language.
It will be interesting to see whether the React Forget compiler (https://reactjs.org/blog/2022/06/15/react-labs-what-we-have-...) will change any of this. I'm curious how this will turn out to work, and if it will remove some of the issues that tend to confuse and annoy people.
My own impression is that the core model of state and rerendering is actually quite nice and intuitive, though often explained a bit wrong. The part that makes it complex and confusing are things like callbacks, which can trigger lots of unnecessary rerendering and force quite some boilerplate if you want to avoid that. If you can remove all the stuff around trying to avoid rerendering unnecessarily, React would be a lot simpler.
I also think that people are too quick to use the wrong tools for managing state in React, e.g. Context to avoid a bit of prop drilling.
React enables v=f(s) by making DOM updates faster. v=f(s) was always a good idea, but before vDOM, replacing the HTML of the page on every little state change was too much for the browser.
- Now you describe your views as pure functions of their inputs and stop caring about them, React cares about them. You know that with the right s, the right v will follow.
- You need to care and manage your app's state carefully, yes, and everything goes in there. Fortunately, patterns and frameworks like Redux make it releatively straightforward to do this.
You can still make a mess, sure, and make mistakes, etc, of course. No silver bullet. But you can now deal with those two separately. If you start fetching data from your components directly you're back in jQuery hell with extra steps.
I came from the video game world. I used to program for the Playstation 1 and 2. For me, all these reactive frameworks are baffling. Is it weird that I just prefer immediate mode UIs and roll my own state management and "reactivity" on a project by project basis?
I may be wrong here, or it could be my age showing, but I feel like explicit UI systems like that might be more verbose, but I find them more accessible to dive into and less "magic".
I'm totally lost and baffled by everyone's enthusiasm for these increasingly arcane and complex abstractions. I suppose they are necessities that arise when you reach a scale that I have not yet encountered (I work on small to medium sized teams of a dozen or dozens rather than hundreds of programmers).
Having used reagent, watching the React space evolve is like a bricklayer watching a constant stream of innovations around mud. Sure, you could build foundations with bricks, but why do that when you can use a fancy mold and pour mud into it? Why have clean blocks when you can have sticky, messy, dirty goop?
Alas, castles and fortresses have been built with messy goop, and the amount of goop-specific tools and goop slappers far outweigh the bricklayers. So I too slap goop.
This kind of thing is possible because the React state model ultimately hasn't evolved too much itself; only the easily-accessible user-facing parts of it.
I've been running a mobx-react setup for 7 years. It's been thru a few syntaxes but it behaves identically. Minimal rendering, observability, I find it the most intuitive state management pattern.
I don't know. The guy just doesn't like hooks? I think hooks are absolutely amazing. I'm in charge of a very large codebase. We are currently migrating it from CRA to Remix, about 40% done. When I compare my Remix code with the old code, it's EVEN BETTER than the old stuff. Despite the gigantic codebase, I am always able to figure out what is going on (thanks to hooks, just read the function from top to bottom), where the data comes from, where it goes to. It's just all around a good developer experience. I have a feeling this guy just yearns back to simpler days where websites where static HTML & CSS.
I have also been able to consistently hire absolute greenhorns right out of tech bootcamps with zero formal computer science training and they were able to build features that made our company real money and push to production within the first two weeks. React can't be that bad.
Now that we threw out react-hook-forms (Remix does it all fine with default form APIs), Apollo (don't need their caching any more, so just sending plain GQL requests via fetch does the job), Redux (Context API is just fine), emotion (TailwindCSS is so so so so so much better)... our Remix codebase is basically pure HTML and Tailwind's css classes. It's a bliss.
I've been mostly using React from ClojureScript, via reagent and re-frame. I've mostly avoided the hype of hooks, except in interop where they've been a pain. And I second the sentiment of Mike Thompson, who says [0]:
> Humans have a cognitive bias: "what is focal is presumed causal".
> Political leaders know this. They like presenting good news themselves because they like to be "seen" as causal of good stuff, but they'll get a press secretary to deliver bad news. Movie directors know how to use this when framing their protagonists within the story.
> Unfortunately, the React team have lost themselves in this bias. They keep trying to make the most focal part of the system (components) also be the causal part. Please stop doing that! It is a mistake. Events are what's causal - they embody the user's intent.
> Just to be clear, I love React. What an utterly brilliant idea and great execution. I'm deeply grateful because, wow!, did it change things. It is just that I preferred React when it was only trying to be the V part of MVC. Everything since has been downhill.
Can't say I relate to this, interesting perspective nonetheless.
This line however "It is not obvious that your component re-renders on state updates." is kinda strange, maybe it's not obvious if you didn't read any documentation or tutorial?
also "You could build your own framework in an hour using reactive primitives [...]" is the same as when people say "just make your own sorting algoritm", yeah sure you can get the exact behaviour you want, but come on.
I’ve happily used MobX for years. It comes with its own quirks but almost completely bypassed the awfully awkward state management that is React. Made my life 200% more enjoyable!
It's an additional layer on top of MobX that adds strong typing. I've been using it for an open source video annotation project and it's been amazing for keeping track of local state, cascading calculations of things.
Here's my "models" directory for it if you want a taste of how it works:
Thank you! If only I had been a better programmer back then I'd probably have opted for a solution like this. Instead I had worked out through the year and made some highly custom system that resulted in very similar patterns. Too ingrained in my app now to consider new options but might be a good idea to build on top of those next time around!
React hooks could have been very different with very minor touches. But at this point, a structure has emerged where you need to make extra efforts to work steadily. It wasn't like that at the core of React. Class components had their own problems. But you know how to solve them. I don't think this applies to react hooks.
For reasons that I can't quite explain fully, I like angular much better. For me it's a shame that react won the battle and is used at every company now.
Angular seems like a step back to me. The MVC thing, while fine, introduces extra hiccups. Creating generic UI components is pretty tiring and using Angular material is pretty much your best option.
Upgrading to newer versions is a pain and also finding well supported third party libraries. React is much easier to work with since you don't always need to reinvent the wheel for time consuming things.
Hooks and simple state management with Jotai are also much nicer to work with than RxJs. RxJs requires a strange mental model and a lot of verbose code and functions.
Angular is kinda like Java, more code for less features. Great if you don't wanna think, meh if you want something exciting and new.
For me, Angular enforces a rigidity that seems oppressive at first, but once the codebase grows in size and complexity it all makes sense. In React I might find API calls nested in component effects, setting context that gets consumed or overriden god knows where down the tree; in Angular all of the API calls and state is isolated in high level services and it's very easy to follow the logic and track where those get injected and consumed. I also find it much easier to mock a service rather than mocking contexts for testing.
You still have to reduce the entire state no? I would imagine it to be something like:
struct A {
b : B
}
impl Reducer<Action> for A {}
impl Reducer<Action> for B {}
Now the reducer logic is spread out across the state.
Sure, every sub-state now need to handle Action every time but with tools like ADT and pattern matching I don't think its as bad. I feel like this will be cumbersome, but the complexity should scale linearly.
The post is excellent (and I actually got quoted in there from my "Rendering Behavior" article), but the title seems completely over-editorialized? There's not even a mention of the word "fractal" in the post.
We've reverted the title now, in keeping with the site guideline: "Please use the original title, unless it is misleading or linkbait; don't editorialize." (https://news.ycombinator.com/newsguidelines.html)
(Submitted title was "React is a fractal of bad design")
How are you being held hostage? I'm currently using React, but I've used a lot of other frameworks in the past, and expect I'll be using a lot more in the future (Svelte is currently topping my list of frameworks to check out).
I started out in these sort of frameworks doing Angular 1 in 2013. Did a lot more Angular 1 projects in those years, and really got to know the intricacies of the framework. Was ready to switch to Angular 2, but instead I ended up doing some native JS web components, a little React, then some Vue, and now some serious React.
I've got to say, I liked the little React a lot more than the serious React. All those useEffects everywhere don't make the code any more readable. There's layers upon layers upon layers of components and abstractions and layers in between. It comes across as less organised than my old Angular 1 or Vue code did, though that's probably also due to the size of the code.
Anyway, I'm not being held hostage by anyone. Next project I hope to be doing something in Svelte, but maybe I'll end up doing something completely different. Maybe some Kotlin? I still haven't used that.
One alternative is the Model-View-Update framework developed in the Elm language [1]. A few years ago, it influenced Redux [2], but JS doesn't have good ergonomics to support it, so people complained it was too verbose. Anyway, I brought Elm to the company I worked at two jobs ago, and it worked very well, since it is conceptually very simple. The experienced developers loved its explicitness, which made it possible to build a very intricate app from just a few dependencies, which in turn allowed the company to have a very fine-grained control of the UI, and the customers loved the result.
On the other hand, other less experienced developers didn't like Elm so much because React allows you to write your app with fewer lines of code. The article from this discussion explains well that React (especially with hooks) hides complexity, which bites people later. At that time, it is perhaps too late to switch to something else.
Needless to say, I haven't been able to convince any other employer to use Elm, and then I see issues popping out all the time that would never happen with it. Such a waste, just because people like shiny toys and just follow what others around them are doing without thinking too much.
I'd love to use Elm, but I'm completely uninterested in building off something where low-level hacks are impossible.
For example, I recently wrote a react component that diffs it's new state against the previous state and then calls an imperative map API to bring it into alignment. Ideal, no. But I'm not going to wait for the compiler devs to do something perfect before I write this app.
At first, it felt to me that the broad stroke criticism of React expressed in this post was of the very familiar type that’s been around prob sky since it’s first release: that React should be more than what it’s ever intended to be, which is a library that outputs UI as a function of state (input via props). By offloading the responsibility for all the rest of it, e.g. managing state, remote fetching, etc. onto the person implementing it, React has always left a lot of room for frustration and poor decisions.
But I think the criticism here is a bit sharper and more pointed than that. The author isn’t expecting Reach to do something for which it was never intended, I think. Instead, they’re saying that the abstractions (hooks in particular) that have evolved over time expose unhelpful interfaces that either conceals too much information, encourage poor patterns that lead to bugs, inefficiencies, etc.
In other words, the criticism isn’t of React’s explicit decision to offload responsibility outside the scope of outputting UI, but rather that it’s evolved to make handling of those responsibilities more challenging.
I think that’s a bit more serious than the former critics and worth at least considering. For my part, I’ve found little substantive advantage to hooks and do think they hide a lot of bugs by making implicit things that should probably be (and, once upon a time, were) more explicit.
1. I’m not sure what they have in common with each other. What exactly is a React hook. Nearly every hook is its own thing, with its own purpose, use, etc. With the new “use” hook, even the original hooks rules don’t apply anymore.
2. Related to the above, every hook is an entirely new concept. Learning react you would think once you learn “hooks” you will be able to understand basically what they did. Much like once I learn “classes” or “functions” I can figure out what they are. But every hook is its own concept, with its own rules, and gotchas, etc. Sometimes I wonder if the reason they’re called hooks is to present them as a single
Concept, otherwise it would be too obvious that React replaced a few concepts, state, and component lifecycle, with about 3-5 concepts in the library in the early versions, and many more now, with an infinite possibility of concepts through custom hooks.
3. No one in the React world seems to have a clear mental model of what hooks are. useEffect is the most egregious here, but the name (and the original React docs) indicated it was for side-effects. But then it’s also used for lifecycle management. Finally, it appears that now the React devs have started pushing the idea that it’s to keep “components in sync with an external system”. And useEffect is probably the most used hook outside useState.
To be fair, usually descriptions of concepts can change with time. But with useEffect it’s not just the description that’s changing. It’s the entire mental model, which makes it seem that the React devs themselves are not clear what useEffect is supposed to be.
Fundamentally, hooks seem to be a bunch of ad-hoc solutions that React devs use to solve specific problems they notice in the wild. But there doesn’t appear to be any fundamental consistency to what they really are.
There is way too much local ad-hoc state in modern web apps. (Ad-hoc as opposed to persisted state.)
The first example of UI frameworks is always the `counter`, but it's always the least realistic scenario you encounter. Almost every app involves retrieving state over the network, sharing state in multiple places in the app, and how this state is CRUDed.
The reality is that all state is very interconnected.
Ideally you want fine-grained reactivity for every rendered UI element, that ultimately reacts to the changes in a database in the cloud.
And every piece of state should ideally be persisted. Even things like dropdown menus and their state.
The simple solution to all this is to store all state/data in a single database on the client. Every time you render something from the database, a component should have its own "view model". And this view model should react to changes in the database.
This "view model" also shouldn't be hidden inside components. There should be one place where you can view all the view models throughout your code. And see the interconnectedness. In a visual way too.
Maybe we went off-track when we started to merge the view/model/controller in the same file. We create hierachies of views, and then they need to get their data from this view hierarhcy. But instead they should be getting their data from a central database in as few transformations as possible.
The mistake people make is trying to make components isolated and decoupled from the rest of the app as a principle. It sounds nice, in that when you work on a single component, you only have to worry about what props are being passed to it. What makes apps complex though is data transformations. Ideally you want data to be as close in shape to the underlying dataset as possible. Otherwise caching/memoizing becomes very difficult, and this is usually the cause of many performance issues.
As someone who has used Vue full time for the past... going on 7 years, and before that used a probably-little-remembered framework called Mercury,* I feel like I'm missing something.
I wonder how many of the issues people have with React are due to it not being built on a state management library - like Vue is, and Mercury was.
The rendering is whatever. Templates, JSX, it doesn't really matter. Mercury used hyperscript and we got by just fine. But state management is critical, and React seems to leave it completely up to you.
Vue added a hooks-like API. While I haven't used it in anger, I've toyed with it. And it sidesteps some of the weird React hooks caveats... because of Vue's reactivity system. Huh.
*With a brief interlude using the original Angular, which I did not understand then and still do not understand looking back from today.
Lovely read. I’ve been in TS and React land for a year now and it’s been so great but as our codebase grows I do see the walls closing in a bit. Signals are interesting, I wonder what react could look like if they supported them more natively in the library in the future.
A simple server side template render is more than enough than 99.99% of SPA apps need for a fraction of the complexity, bandwidth or brainpower spent minding performance.
> Frameworks like Preact, Vue, Angular, Marko, Solid, and Svelte have all adopted some form of fine-grained reactivity. They’re called signals, stores, or observables. The semantic differences might be important, but I’m going to refer to the concept as a signal.
I would call this concept noodle. Because when there's a lot of them you get back your tasty spaghetti. The whole reason for React was avoiding it whenever possible.
I have been using react since 2015, hooks for the most part seems like a miss.
I use sometimes, but for the most part is overused feature.
I think thats a symptom of a problem with the front end community, people get too attached to the new thing and try to make it the standard instead of building something stable and concise.
Im tired to having to rewrite a code because one library that I had to upgrade decided to migrate to the "new thing"
The composability of hooks, which was one of it main selling points, is also my main gripe with them now. I often have to wade through multiple levels of hooks to figure out what's really going on.
And using it professionally for years now, there's still some cases I can't wrap my head around. And the mental model is just a bit "off". Like, the same function is ran multiple times, but with different behavior (like a useState only uses the parameter the first time the function is ran) which is very unclean.
It's not even orange for me. I changed the "topcolor" in my profile settings to d0c8b5 - a darker shade of the body background color. Now the only orange thing is the Y logo. Much easier on my eyes this way.
React is the most "framework" framework out there especially when hook come out, it completely dictates you how you write your program, and it's very easy to go into traps if you don't know how hooks are implemented. I'd much rather use a reactive UI framework like Solid because they use a much simpler concept
> I recently read someone’s astonishment at how smoothly the React ecosystem’s transition to Hooks was - how everyone was unilaterally in agreement on its benefit. This is not the past I remember. I remember quite a bit of a contention. Particularly on the orange site, but not exclusive to it.
> On every key stroke we have now rerun toTitleCase in every component.
In game dev you run millions or even billions of computations 60 times a second. If running toTitleCase three times every key stroke is an example of a compounding performance problem in React then surely the problem must lie deeper.
> What would framework-integrated fine-grained reactivity look like? Probably something like Solid.js
It would look like JavaFX which has had this exact approach since it launched over 10 years ago as well as a large library of observable operators and collections complete with delta events, the ability to define components with a "shadow DOM", with custom CSS properties, using both JSX-like widget-oriented markup and code, and a whole heap of other things the web community has since slowly rediscovered. Here's the high level observable operators API (there is a lower level one that lets you define custom operators):
You could also write that in many other languages like Clojure (with cljfx for FP fans), Python, Ruby, JavaScript, and of course Java. It would be less verbose if I used a library that better used Kotlin's features, but the goal here is that you can look up the APIs from the link above (there are a couple of implied static imports).
So not much different, but it demonstrates how the text property of the label is bound to a dynamically computed string which is in turn bound to an observable number. When the timer fires, the count increases and the label is recomputed. Everything is done that way so layout computations, for example, won't run unless the size of the label changes. And that's it - no need for VDOMs or prop drilling or state memoization or any of these other performance hacks.
At some point you'll observe that this seems a lot like "reactive programming" as used on the server side, and then might want to explore a library like ReactFX which connects these two worlds together.
There are some other nice features in this type of toolkit that the web community seems to be heading towards. I'd be willing to bet a lot that at some point they'll even reinvent inheritance under a new name, because being able to write code that's generic over component trees is really pretty useful. The hooks/functions model totally wrecks that and has led to this explosion of "design systems" (otherwise known as themes that bundle half a widget toolkit), none of which interoperate properly or can be coded against in an abstracted manner.
None of this is to say that FX is perfect or that React/SolidJS etc are the wrong tools to use. You can run FX apps in a browser using a form of server side rendering - check out https://www.jpro.one to see a fully crawlable website that's actually implemented using JavaFX on the server with no frontend/backend split existing at all. But it only works well if you don't have a fast and reliable server connection, plus a server with plenty of RAM and CPU. Alas browsers pull all sorts of mean tricks to keep people locked inside the HTML5 sandbox so JS frameworks aren't going anywhere, but it would be nice if that community spread its wings a bit and looked at prior art from outside their language. GUIs are old and the challenges involved in them aren't new, and from the outside it looks suspiciously like there is no real progress being made here, only wheel spinning.
Yep! I’m full stack and have no clue why some people want to say frontend engineering is “less than” backend. It’s all a means to an end. The product requires both sides equally in most cases, and neither side is trivial.
If anything, what I miss from doing "backend" is the ability to just pull in whatever library I want to solve a problem.
I need a web server to work by slapping together fifteen Java libraries from thirteen different code houses and writing an absolute Shoggoth of shim code to convert between their types and classes? Sure, whatever, datacenter storage is damn near free.
I need to put code on a client machine on the internet? You'd best pick one of these date libraries, because there's no way in hell we're justifying shipping moment and Joda down the wire.
That is honestly hilarious, I took a look at their other comment (singular), and this person waited literally over ten years just to post this comment. Wow.
Meanwhile us Vanilla.js'ers are still wondering exactly what a front-end framework does for a site that displays some text and some images.
It seems like the framework culture is driven by the search for a silver bullet that makes problems go away. But each solution to a problem always comes with its own set of problems, only these problems are initially unknown. So you trade a set of known problems for a set of unknown ones.
It is possible that these new problems are lesser problems, but this is hard to verify upfront, and the nature of being unknown makes it a lot harder to deal with them preemptively.
So anyway, you have your framework, you have used it for a while, and you have learned about the previously unknown problems that it causes. You could rejoice that you now have this knowledge, and therefore have a reasonable shot at working around the problems. But instead you ditch your imperfect framework and search for a new one, beginning the cycle anew.
People tend to compare these frameworks on things that don't matter - often it's performance. We used to compare React performance to AngularJs performance too, which was meaningless.
VDom is nice. Reactivity in signals is nice. Limiting rerenders is nice. But I choose frameworks because of developer ergonomics.
The killer feature for React was - 1. JSX - typing and auto-complete for components, colocation. 2. No direct dom access. (Good bye $element)
Most frameworks outside react still use templates. Even when they support JSX like syntax (aka vue 2.0) the default are templates. Templates are a no go for me. I use them for blogs or static websites, but applications are easier to make and maintain with actual javascript.
Luckily none of the other frameworks, even Angular, have rampant direct dom access anymore.
Hooks aren't a problem in general. It's just the useEffect hook. Unfortunately that's a big problem. That hook should never have existed. And it was clear from the start it'll be a pain from the limitations around it. It requires a mental model detached from everything people are used to and from other things around it.
When using React I usually just use MobX and everything just works.