Hacker News new | comments | ask | show | jobs | submit login
None of my projects want to be SPAs (whatisjasongoldstein.com)
367 points by thequailman 10 days ago | hide | past | web | favorite | 341 comments





This may be a mean thing to say, but basically I think SPA's are massively overused, because developers want to demonstrate that they can do them. Why? Because big companies like Facebook and Google use them. Why? Because they actually are doing things that require them. 99% of the SPAs in production are things that should have been done the old Rails/Django/Laravel way, but that would not set you up as a developer who can do SPA's.

I have also witnessed discussions where management admits that they want something done in an SPA so that they can show that work to their investors, as a means of getting funding to do other projects. So basically the same reason, except for managers to impress investors instead of developers to impress potential employers.

Not saying all SPAs are mistakes; some uses clearly are not. But most of them are.


> This may be a mean thing to say, but basically I think SPA's are massively overused, because developers want to demonstrate that they can do them.

Unfortunately this is another side effect of the broken hiring process in IT. Recruiters are scanning resumes for the hottest buzzwords, hiring managers want people who have experience with whatever is currently hyped, so developers naturally steer towards those technologies.

So a developer may even be aware it doesn't quite make sense to use a single page architecture, but they know that if they have it on their resume it'll help them make more money at the next job.

It's a whole maladaptive signaling phenomenon that arises out of organizations overvaluing the wrong things in hiring.


I agree. It's also not simply a matter of making more money on the next job, it can be a matter of having a next job.

Some years ago, 3 of us picked React for a startup. I consider it the single biggest mistake in my career, but we picked it not for the reason you mention. We didn't think that far (I was perhaps a junior, but the others weren't). It was just a matter of picking the frontend framework that we liked the best (I think the options were between Backbone, Ember, AngularJS, React). In our minds we did pick the simple option.

Some may be aware, but certainly not everyone.


> I consider it the single biggest mistake in my career

I have to ask... what went so wrong? If you had a time machine, what would you tell your younger self?


Oh I'm so sorry, I didn't see the replies.

It was a mistake because we needed to move fast and figure out if we had something or not. A simple CRUD website (say Ruby on Rails, Elixir/Phoenix, or even straight up Node/Express) would have been faster to build and iterate on.

There was one section of it that would benefit from being able to work while offline, so that could perhaps have been built as a small SPA. But the rest, that was in hindsight a mistake.


If you had to redo what would you pick? Why not jQuery?

jQuery would have been fine, but honestly the website did not need that much js (if any). It should just have been a CRUD website.

100% correct, and I'm guilty as charged. If leadership likes the sound of SPAs, and my next job wants me to have experience with SPAs, I'm using SPAs.

It can be the same story on the hiring side: Teams will decide to build $new_thing using $NEW_THING! simply because they know it will help them attract more (and often less expensive) applicants.

Yeah, some people go so far as to directly claim that something is good because Google uses it. And when Google uses it, it probably IS good for solving Google's problems. But most people aren't Google and don't have Google's problems.

Ugh… We've had one of those developers. Now we're stuck with a legacy GWT¹ SPA that sucks the life out of any developer who touches it.

1: Google's abandoned webapp toolkit where you get all of the drawbacks of writing Java code with none of the benefits.


GWT ouch. Or as I call it "get with the times!"

> some people go so far as to directly claim that something is good because Google uses it.

Angular everything and everywhere and sprinkle it with Material Design!


Not a fan of Angular, am a fan of most of Material Design.

Yeah... "because google|apple|microsoft|ibm|facebook ..." is generally a bad idea on its' own merit. I do like React though. I like similar JSX tooling around inferno and preact too. It's just something close to what I wanted when first playing around with e4x with flash/flex and mozilla browsers.

Do Google still use their closure library + compiler on all their big properties? https://github.com/google/closure-library/

I'm learning Clojure at the moment, don't think I would have heard of Google Closure otherwise


Closure language and closure compiler are two different things. One is a lispy functional language with its own syntax, the other is a jsdoc typechecker and optimizer/monicker.

A lot of what clojure does, Typescript does it really well with it’s types in jsdocs.


They're related. The ClojureScript compiler uses Google Closure as a backend and runtime library

The other day I was arguing this exactly in a thread here about Ruby. People argue that Rails is outdated and is irrelevant for "modern web development", even though the web is not as modern as most people might think. Even what Facebook does, the only really hard part is the sheer scale they operate at. Facebook (the website) is not a single page app and other than the scale could be done in Rails with some AJAX sprinkled in or even Wordpress with some plugins.

People use SPA frameworks and make SPAs with them and those SPAs end up functioning exactly the same as any Rails/Django/Laravel site except the URL bar doesn't change. MVC is still the way the web is built, except for the people who got bored and wanted to make web development even harder than it already is.

YAGNI.


I've started thinking of this phenomenon as "blog driven design". It's what happens when you fall into the assumption that what bloggers are writing about is what everyone is (or should be) doing.

The problem with that is, blogs are a poor barometer for that sort of thing. Nobody needs to write new blog posts about tried-and-true things that are already plenty well documented. The more solid and stable a technology is, the less incentive there is for anyone to bother writing how-to blogs about it.


In order to have dynamic UI you either have to use jQuery or SPA library like Vue or similar.

For me the major advantage of vuejs over jquery is the way data drives UI


But... people had dynamic UIs before jQuery and Vue. The main benefit of jQuery was back in the days when the browsers were so different from each other, but that's not the case anymore. I'd recommend learning some vanilla JS before thinking that you need jQuery/Vue/React to create dynamic UIs.

The difference is imperative vs reactive UI. The impact of this is hard to overstate.

Why do you need jQuery for this?

You don't strictly need jQuery for this. jQuery simply has a terser API than the standard DOM. That's why I still use it.

sure, although modern browser apis mean the url bar can change in a reasonable way

What about tabs? SPA can make tabs troublesome. If I can't open a site in tabs it is broken to me.

I'm not sure when/why tabs should be an issue... it depends. To me it's a difference between localStorage and sessionStorage for the most part.

If links don't fully address an item then opening it in a tab won't work.

That isn't a limitation of SPA or browser based apps though. For that matter, even having an option to open an app multiple times is often a limitation of desktop apps. That doesn't make them somehow deficient as a platform.

It does. You don't open the "app" multiple times, you open lists or records in separate windows and/or tabs. That is a thing in desktop apps also. SPAs usually break it by tunneling everything through a single url, perhaps with anchors.

But opening lists/records in another window/tab isn't a limitation of the browser environment, or SPA in particular. With proper router/caching in place it can be done within a browser app as well.

Browser-side routing/state management is a solved problem - SPAs can make tabs troublesome if the developer didn't put in the effort.

For God's sake, STOP trying to re-implement my browser's interface with Javascript! I don't want you to "put in the effort" to make my URL bar, back/forward buttons, and tabs work the way they naturally do in my browser; that's what my browser is FOR! Even when the developer does put in the effort, the results are usually _just_ different enough in various subtle ways from the browser's native behviour as to be annoying.

Just build a normal website and let my browser do what it was built to do. The APIs that allow SPAs are great and useful. The Pixlr online photo editor has a good reason to be a SPA, and that works great for it. Your forum/email interface/management API would work better as a normal website.


> Your forum/email interface/management API would work better as a normal website.

Good for you with your fast, always-on internet, I guess. Some consumers have to deal with expensive and unreliable 3G internet (that downgrades to 2G occasionally) - an offline-capable email (or management) SPA is indispensable for them. Sure, you could write 4 native offline apps for MacOS, Windows, iOS and Android but that is a bigger investment than targeting browser standards.


SPA is orthogonal to storage, nor are lightweight web techniques exclusive to it, and often in opposition. Native email clients already exist of course.

Using web API means tabs work even if the developer doesn't put in the effort.

Having the address bar behave sensibly is one of guiding principles of the Ember JavaScript framework. A good modern SPA framework should be able to handle proper routing out of the box.

> I have also witnessed discussions where management admits that they want something done in an SPA so that they can show that work to their investors, as a means of getting funding to do other projects.

Absolutely. This extends well beyond SPAs, too, in my experience. I recently burned part of a month explaining to my senior management chain why you don't just, literally, "do machine learning." Of course, it turns out that the ask was coming from the C-suite, who wanted to put it on a slide somewhere because "everyone is doing machine learning, we need to do machine learning."


I do machine learning consulting and I see the flip side of this. I get new clients reaching out asking me to "add some AI" with no specific use cases in mind other than satisfying their investors that they are "leveraging AI."

Had a client that wanted a machine learning solution to determine if one name that was in one list was also in another list...

lol... Train your model with the dataset of "another list" i.e. populate a lookup table. Slap a sigmoid on top of that boolean "presence" result. Perfect precision/recall!

In my experience the C-suite people don't even know what machine learning or AI even is. Why don't you just tell them that you've incorporated machine learning into your website? It's not like they would know the difference.

Ha! I've seen higher ups not even bother to go to that length. They checked the "validation to put it on a slide somewhere" box by just implicitly rebranding AI to be short for Augmented Intelligence. In the context of executive presentations the play on semantics tends to get lost, while the "We do AI[1]" remains true!

[1] https://www.informationweek.com/big-data/ai-machine-learning...


It's similar to people gravitating to NoSQL when they probably actually needed a relational database because they don't really think about their data model and how it will be accessed.

That being said, as someone who has done a lot of infrastructure work, I do like web technologies that can fit into something like serverless and Ruby/Rails really isn't there. Speed, file size, and boot time all become much more important. Or if you can make it work, fully static pages that can live on S3/Cloudfront and any dynamic needs are abstracted away to API gateway/Lambda and pulled in.

I would much rather have an app running inside of Lambda instead of having to manage a load balancer and AWS auto-scaling, or even elastic beanstalk.

So many problems can be dissolved down into people picking the wrong tool for the job.


Yeah to be honest, even RoR/Django/whatever is often more than is necessary. Sometimes static HTML/CSS is what's necessary. A lot of the time, really. I wonder what percentage of React websites could be well served with static HTML and at least one employee who knows HTML.

Microservices are in the same camp. I use them, I love them, I advocate for them. But microservices don't make any sense if your application doesn't call for it or if you don't have the orchestration infrastructure to roll them out and test them easily.

I've worked at places in all four quadrants of should/shouldn't and do/don't use microservices.


Yeah microservices is another one that suffers from the One Solution To Rule Them All mentality.

They're GREAT when they're the right fit.

Most websites aren't really a right fit and do fine with a classic webserver->DB setup.


Unfortunately for most devs, the only way to set yourself up for "better" work later, is to force current mediocre work to use the tooling of the future work. In 2019 if you have on your resume that you're only familiar with Rails and ERB-sites, and you suggest using them for pretty much everything, you'll never get a new job. At a certain point, career-minded devs have to do the "resume driven development" game a little bit, if only to know what others are doing.

But in reality most work is very simple. Most work does not require new shiny technology. Most work is insanely mundane.


Depends pretty much where one wants to work.

Outside the software business, on companies whose focus is totally unrelated to software, no one cares that much how things work.

They just have a couple of devs, or hire some freelancers do do some stuff, no matter how, it just has to look pretty.


And they pay them peanuts compared to software businesses.

Speaking from experience, not necessarily.

I feel like this is pretty specific and/or lucky. In my experience, the companies you're referring to also have a person that's worked there for 15+ years and "architected" all of their infra from scratch, in an incredibly unmaintainable way. Sure, they could've done whatever they wanted, but that does not mean that it's better than the alternative.

You're not wrong.

There are clearly good uses for SPAs, but the author is totally correct that most sites are "open, check, close" experiences.

If it's not essentially a web based, desktop app...it's much harder to justify. Real tools. If it's not a tool and the user workflow is "open, check, close"...it's serious overkill.


Having worked on web based applications (not sites) for a couple decades, I have to agree... I'm a fan of either SPA + Node API (other APIs behind it as needed) or, can it build to a static deployment. I push to one end or the other.

I don’t get the hate against SPA’s. An SPA done right offers amazing interactibily and instant navigation to new views. You already have the templates cached. They probably load from a cdn with good caching policy. If done well you can totally run offline.

Sure you can build with php, laravel, django. The promise of SPA is a clean separation of UI from the APIs. The same REST APIs that external customers use is the same API you develop on. See travis-ci as an example. It’s the same api that the mobile apps can use.

This separation allows the api to return very lightweight stateless responses. You can scale much better when there is less state kungfu.

The UI can manage the state in very responsive manner. No round trips, instant 60fps render.

And no JavaScript is not slow. It’s just that people don’t know it well and end up loading megs of bloated libs with a 1000 ad tracking libraries.

Don’t throw the baby with the bathwater.


> An SPA done right offers amazing interactibily and instant navigation to new views. You already have the templates cached. They probably load from a cdn with good caching policy.

Most of the time I find the initial delay loading/parsing the js to be more problematic than the often tiny speed increase of subsequent loads.

Furthermore, these days it takes minimal to no tweaking to get server-side rendered pages to load fast enough to barely notice the difference (in particular if the client-side is retrieving and parsing JSON in the background through an API request). Perhaps non-webdevs are even less likely to notice this stuff.

> If done well you can totally run offline.

That's definitely an advantage, but most SPAs I encounter don't offer offline functionality, or it's entirely unnecessary to offer it.

> Sure you can build with php, laravel, django. The promise of SPA is a clean separation of UI from the APIs. The same REST APIs that external customers use is the same API you develop on. See travis-ci as an example. It’s the same api that the mobile apps can use.

In some cases that's definitely an advantage. But it's entirely feasible to build an API-based backend and use that API internally for server-side rendering. If you want an app that plays nice with search engines you have to do this anyways.

> This separation allows the api to return very lightweight stateless responses. You can scale much better when there is less state kungfu.

That doesn't make sense to me. One of the biggest issues I have with SPAs is that you now have to deal with the backend state (DB) and a subset of this state on the client, which dramatically increases complexity (state management, sync, etc.). I rather like the old-fashioned approach where all state remains in the backend, except perhaps for the tiny bits you'd put in a cookie (and I suppose the URL could be considered client-site state too).

> The UI can manage the state in very responsive manner. No round trips, instant 60fps render.

How many apps do you use where you really need anything below say, sub-second rendering? Frameworks like Phoenix and/or caching can be much faster than that even (in the order of microseconds).

> And no JavaScript is not slow. It’s just that people don’t know it well and end up loading megs of bloated libs with a 1000 ad tracking libraries.

Clearly if so many SPAs are bloated Mb-size messes, it's not trivial to solve. And it's a problem you can almost entirely avoid if you keep the rendering on the server. After years of agonizing over bundle sizes, I find it incredibly liberating to not have to think about this anymore (much of the time, anyways).

> Don’t throw the baby with the bathwater.

I do agree that there are plenty of use cases for SPAs, but I also agree with many here who say they're very over-used.

I'll add that there are some interesting initiatives to have 'old-fashioned' applications that also get to be dynamic enough for many if most use cases. Phoenix LiveView [1], for example, takes advantage of very fast server-side rendering, websockets, and sending subsets of the templates as HTML snippets to the client, where morphdom simply diffs the HTML string with the element it's supposed to replace. With great performance.

[1]: https://dockyard.com/blog/2018/12/12/phoenix-liveview-intera...


> This may be a mean thing to say, but basically I think SPA's are massively overused, because developers want to demonstrate that they can do them.

This may be even meaner, but they usually end up demonstrating they can’t. 99% of them are terrible. Even Google’s latest efforts are a bit on the slow, low-information-density side.


Well, SPAs are attractive even for websites that don't particularly benefit from them because of the technical attractiveness of having the website be like any other client that consumes your server's API.

sure but there are very few websites in the world that need to publicize an api, basically only sites that need to be able to function as applications. once you have a site that needs to be an application arguing for it to be single page is not that great a leap.

Sure, I meant to make the point that developers are drawn to SPAs for more understandable reasons than just being a bunch of lemmings.

Also, it's hard to realize how much work a SPA actually entails until you get your hands dirty. SPAs generally sound great on paper from a technical standpoint.


If you have a mobile app, you need an API, even if you‘re site does not function as an application.

The great majority of websites, though, DON'T need a mobile app; they need a website that works on mobile. Most smartphone users are unwilling to download more than a few apps for websites, anyway; if your website is a restaurant, a news source, or anything else that works well on a website, most users are unwilling to download and install your app anyway. So, if you want their business, you need to make your website work for mobile. Once you have done, that, in most (not all) cases, you don't need to develop an app anyway.

unless you use Turbolinks with IOS/Android adapters or another hybrid app alternative

exactly that. since 2012 i build all my websites as SPAs for this reason. more so, i am not even writing any new backends. i reuse the same backend over and over. most websites (at least the ones i have been building) are just CRUD and don't really need a custom backend.

SPAs bring back the client-server architecture we had before the web. you build desktop clients that consume server-api's.

server-side html generation now feels like cruft and an awkward way of building applications.


It should be trivial to build a server-side client app in the same manner, using an API for any persistence instead of directly accessing the database. Most of the full-stack frameworks (Django, Rails, Laravel etc) are unfortunately still conflating the persistent state entities with business logic objects.

you are of course right. there is no stopping anyone from doing that. in fact the university which initially developed the backend i am using has been doing just that, using the backend like a database, creating "frontends" in PHP.

though that doesn't negate the point of SPA which enables building clients that run directly on the users devices and are not hampered by the difficulty of emulating stateful clients on a server.


You are falling into a comfortable trap where it is easier to do the same. If you took the time to learn laravel your development time can be cut in half.

the backend i have is of course written in such a framework. (it's not laravel[0], but it could be)

i am not trying to diss backend frameworks here as bad. any of these would be a good choice for the backend.

the point is that thanks to SPA and CRUD i get to reuse that same backend over and over with little or no modification. (modifications amount to fixing bugs and very rarely adding new features to the API)

my backend development time now is effectively 0!

[0] (i have been working with laravel, django and others (primarily roxen and pike) before, and while i am not a fan of php, i did find laravel pleasant to work with)


You can do this with a non-SPA website just fine if the website's backend is the API client. Sure, it adds an extra layer of indirection between the browser and your data, but if the separation of concerns is really your goal, then that's probably as good as it gets.

[flagged]


Well, with a SPA, 0% of your website may be rendered on the server just like your other clients. That's basically the defining feature, though of course they can be rendered on the server as an optimization detail. They even still use AJAX, so I didn't quite understand that bit.

I'm not sure what you meant with the rest of your post. There are technical upsides to having zero web client presentation logic implemented on the server at all. But it's just trade-offs.

Maybe you're suggesting with your "grunt work" comment that most complexity for most applications lives in the UI rather than the API? I'd agree. It's why there are upsides to keeping UI implementation off the server.

I just like to avoid the HN cargo cults of "this = good, that = bad" and "the people who do $X are probably incompetent."


I think you've hit the nail on the head here. People seem to have lost sight of how a company like Google and a company like say, a local agency don't have the same needs or problems. As you mention, many of these trendy bits of technology are great if you're running a company at the scale of Google/Amazon/Facebook/Microsoft/whatever, but they're overkill for smaller companies or ones with simpler needs.

And yeah, they're also common in situations where they're not the right solution because either devs want to turn their current employer into the next Google, want to build up the CV to look good when interviewing for Google or have a boss/investors who like shiny things in general.


> Because they actually are doing things that require them.

Citation needed. G-Suite's admin pages are half "modern" SPA monstrosities that suck up my RAM and peg my CPU to render a bunch of whitespace with bits of information strewn around, and ugly but functional regular pages whose performance is killed for being framed inside a SPA frankenapp.


Right? Sure, there are Google products that certainly warrant being SPAs (like Google Docs), but the vast majority should be possible to implement without a single line of Javascript at all, let alone as a single-page application.

Not to completely disagree, but I've worked mostly with web based applications, not specifically static content (with few exceptions)... I find working with React and similar far easier for mid-large applications than most of what came before. I was optimistic around ASP.Net (webforms not mvc) and in practice it was a bloated mess without doing a lot of goofy things.

If you're building web applications, it's usually easier to build with components than to think in terms of web controls. If you can separate state slightly from the components even better. This is why react + redux scales well. It makes very little sense in smaller apps, or those that are mostly static. It makes huge sense when you have hundreds or thousands of components, and a lot of application logic and structure.

It isn't just because management wants an SPA... sometimes an SPA is the best option.


In my experience SPAs are actually much more prone to bloat and the resultant performance issues. If you have thousands of components you definitely need to dive into all the complexity of code splitting and server side rendering to make your app fast. You can very quickly find that you have a 4MB JS download.

Of course each application has different needs, but for large multi-developer UIs, I think a better option is to split your front end into distinct server based pages where you leverage React/GraphQL/SPA/PWA features for great DX within those pages. That way you can keep it fast and potentially limit some of the complexity.


I'm on a moderately complex UI right now, that has a JS payload around 364kb gzipped, react-dom, chart.js and material-ui/core bits accounting for most of the heavy bits. I've also been heavy handed with pulling out libraries that could be done easy enough with just React and JS. Svg is suprisingly easy in React, and a couple events while tricky aren't as bad as some other tooling I've used in the past.

Overall it loads in right around 1s, as I mentioned the splitting for async load on demand doesn't work at the moment, which I had the initial load for a page not using chart.js down to around 115kb gzipped. Part of that also includes the embedded SVG icons as well as the JSS for styling.

It's not paying attention when lodash + underscore, + rambda + momentjs, etc. all get loaded via dependencies... most of that can expressly be avoided with specific smaller frameworks and tooling.

https://i.imgur.com/gf5cpNd.png


It's really simple, if you're developing a web app, use a SPA stack. If you're developing a web page, use the minimal amount of tech you need on top of HTML, ideally where the HTML functions without JS.

Does that help much? The distinction between "web app" and "web page" seems fuzzier than the question "would a SPA lib/framework be useful here?"

Is Reddit a web app? Is Twitter? Facebook? They all started with server-generated HTML, all kinda feel "document-like", all of them involve scrolling (if that means anything.)

Is the "app" boundary further along the chain, like at Google Docs?

I think instead of trying to come up with definitions to classify things (and probably argue for the meaning of those definitions from the conclusions we want to draw) we should ask,

- Will this help developers?

- Will this make users lives better?


None of them is a web app. All of them want to provide certain views on their content that are uniquely identified by their URLs. This is especially true for Twitter and Reddit, which both aim to have their views on tweets and threads to be indexed by search engines.

Facebook is probably the least clear one, since they put great effort into eliminating discoverability and accessibility from "outside", i.e. without a Facebook account. They're basically the AOL of today, which was a classic application back then that tried to contain a proprietary "web" of stuff in itself, only accessible if you ran their "browser" application, had an account with them and were logged in, and that "AOL Internet" of course had its own search mechanisms, just like Facebook has its own sophisticated search. However, they're not fully closed-up, they just try really hard to nag you into having an account, which is why I'm inclined to still put them in the "website" camp.

However, all of these web sites surely contain certain parts that are in itself "web apps" and that are pretty much isolated from the basic parts of the site (albeit possibly interacting with it at well-defined points through APIs). I guess that this is a logical result of the large engineering teams that are working constantly on what is basically the same big website - at some point, in order to scale out further, it just becomes economic and practical to effectively isolate certain features into mostly separated "apps".


Deep-linking URLs are available to SPAs as well, though.

I run a somewhat popular media site implemented as an endless-scrolling SPA. Clicking on an image or video opens its detail page in a floating modal and changes the URL. I specifically wanted people to be able to link to content this way, and my SPA will load that modal and the media-gallery behind it.

Quickly, SPA just becomes implementation detail. It's the level of user-interaction that dictates your implementation. For example, if you insist on your site being server-rendered with heavy Javascript that takes over, there may be a point where it would've been simpler for you to just implement it all in Javascript (the SPA).

I could've implemented my media site without Javascript. Or maybe just with AJAX that returns HTML. But I know from experience that, while simple upfront, those become more complicated as you try to build more interactive UX and starting wishing your Javascript had more access to the context. At which point a SPA is just another tool for managing client complexity in some other quadrant of the graph. But there's some nuance to the question of whether your site is or should also be in that quadrant.


It's really easy to throw the baby out with the bathwater in this conversation as well.

A more interactive Javascript-heavy UI can improve a lot of aspects of even websites we consider to be a server-side-rendered gold standard like a forum or message board.

For example, look at the right-sidebar scrubber on Flarum that lets you quickly scroll to arbitrary parts of a long forum thread: https://discuss.flarum.org/d/17745-flarum-0-1-0-beta-8-relea...

Or look at how clicking a submission on Reddit's new UI opens it in a floating modal window so that you don't lose track of where you are when you click out of it. It makes opening submissions feel cheaper/faster to me where, in the old UI, I tended to open everything up in a new tab.

There's a more thoughtful consideration that needs to be had here than just "webapp or website?" Else you're back to cargo-culting.


Both of those are just fixing problems caused by the reliance on JS in the first place.

The first could be done easily with anchor links - if the content wasn't loaded dynamically.

And browsers are perfectly able to return you to the same position in the page - unless it's all loaded dynamically.


Hrm. I apparently angered it by scrolling to fast, and it froze for about a second. I think I prefer ordinary forums...

Or this, this blog post (I wrote) about how Hacker News itself can be improved, and it's about SPA things:

https://www.talkyard.io/-32/how-hacker-news-can-be-improved-...


"Is Reddit a web app? Is Twitter? Facebook? They all started with server-generated HTML, all kinda feel "document-like", all of them involve scrolling (if that means anything.)"

All three of these are examples of websites where JavaScript should be entirely optional. With the exception of the realtime chat functionality in reddit and Facebook, there is very little that any of those three platforms couldn't do exclusively with server-side-rendered HTML and CSS. It might be ugly, but it'd be usable. Any client-side scripting should build on top of that and implement the fancier features.


Yep exactly.

I remember a while back I wrote a blog post where the main topic was "You're not Google (unless you're Google)"[0]. It was related to micro-services but the same thing applies to SPAs too.

[0]: https://nickjanetakis.com/blog/microservices-are-something-y...


Well put. Imagine if every building in a city were built with a foundation capable of supporting a skyscraper, because what if you eventually need a skyscraper?

As someone who started developing not long ago, is there any reason to not make an SPA when it is the workflow you are used to? I just don't see a practical difference between SPA or not. The argument I usually see is that its harder...but like me I expect there are more and more people who have learned this way first.

I mean for SEO sure, but I usually am not concerned with SEO at all.


Building an SPA for every single project is like using a semi-trailer to commute everywhere you go. Sure, it will always get you where you need and sometimes turns have to be taken pretty wide, but what's the downside?

Well, if you're destination is just 2 blocks down the road then why not walk? If you just need a simple page and the content doesn't need to be updated often, why not some flat HTML/CSS/JS?

Many times SPA frameworks are used because it's flashy and more exciting than writing basic html and css, but more often than not that's all you need.


I didn't consider small static sites. I agree with that and have done some landing pages that way that stand in front of SPAs. I guess I was commenting on OP wanting to use Rails or Spring MVC for views instead of only using them for APIs.

I'm not sure what the term for it is, monolith maybe.


I believe the term would be "Server-rendered MVC framework". I think the argument for server-rendering is simply productivity. You can probably get stuff done about twice as fast if the use case fits the paradigm.

It's nice when I don't have to enable JavaScript just to use a website. My battery appreciates it at the very least. Forcing me to run arbitrary Turing-complete code from the Internet just to, say, read an article or buy something online is not okay, especially when that code exists solely to either 1) spy on me or 2) reimplement half of my browser.

It isn't a mean thing to say, it's the truth, and the insanity that is modern software dev needs to have its truths spoken more often.

Back when I was doing React, what pulled me in was that it WASN'T a framework for SPAs. What I got from it was the ability to build UI widgets (components, in React terms) that worked within a page, and were composable with other UI widgets.

With that approach, you really wanted to keep every component self-contained. That meant a lot of bookkeeping with passing events back and forth between parent and child widgets, but while it was a lot of typing, it was all fairly easy, and if I wanted to change how an event was handled, it usually only involved a component and MAYBE the components immediately above or below it in the component tree. Data passed further than that was generally wrapped in objects and therefore didn't require code changes.

Then introduce Redux and similar frameworks, and I totally lost interest. It's as if the entire React community forgot all the lessons they learned writing Python and C programs in college and went back to creating global state. What in the actual hell? I wrote a good amount of code in Redux, too--I worked on teams that used it--so this wasn't just pre-judgment. These frameworks add a huge amount of hidden global complexity just to avoid having to pass parameters to components, which is the simplest thing to do.

And once you're doing that, you HAVE TO write an SPA, because any part of the page you want to be interactive gets pulled into Redux and your JS eventually eats the whole page. It's an infection.

When writing JavaScript now, I sometimes end up rolling my own version of the component style. It's an effective design pattern for UI widgets. But it hasn't been worth it to use React for a while now because the tooling and tutorials are all too conflated with Redux and similarly awful tools. And on a team, there's always the worry that someone on your team will infect your code with Redux and it will grow and consume your entire site. It's a real shame.


> These frameworks add a huge amount of hidden global complexity just to avoid having to pass parameters to components, which is the simplest thing to do.

Redux offers a few benefits:

1. Allows you to keep your global application state 100% predictable by treating it as a pure function of an event stream (dispatched actions). This makes it trivial to test.

2. Allows you to "time travel" the state of your store using the Redux dev tools by replaying/modifying the event stream. You can also set up QA folks to export their events so that developers can reproduce any bugs in the global state 100% reliably.

3. Allows you to access global state without explicitly passing down props from great-grandparent to great-grandchild.

While I'm not a fan of using Redux for everything (it does have costs), you mentioned only the most minor benefit. If you only want #3, you would just use React's built in context API.


I have yet to see a long term project built with Redux that was maintainable. That seems to be the common denominator in React projects that do not survive technical debt accumulation.

The issue with Redux is that it encourages side effects in components. After a while people are dispatching all over the place and you end up in a similar situation as you were with keeping track of JavaScript events. All of a sudden something stops working because someone removes a component that is dispatching on a timed interval etc.

If you can convince and enforce that all Redux activity only happens at the root component, you should be okay. But the reality is that once you have the discipline to only mutate state in your root component, then setState tends to be more than enough for anything but very large and complex interfaces.

With that said this article has the author implementing their homebrew bespoke event system which is likely even worse. This was a very popular and much maligned anti-pattern during Angular 1.x days. This article is suggesting the absolute worst possible idea for maintenance.

What kills the maintainability of React and similar frameworks is tracking down what component did what. Unfortunately, in real world examples, in my experience, Redux increases that issue and ultimately leads to a very difficult application to maintain long term.


> I have yet to see a long term project built with Redux that was maintainable.

The only maintainable projects I have worked on in terms of web apps have been with Redux.

Redux is not great for simple projects, it is great for medium and large scale projects.

> All of a sudden something stops working because someone removes a component that is dispatching on a timed interval etc.

That's the problem: react and redux are not enough for large projects, you also need a way to manage side-effects. Incorporating `redux-saga` would fit that purpose.

React, redux, redux-saga -> this is the recipe for large scale applications that I have used, built, and helped maintain with success.

One of the strongest benefits of redux is being able to see every single event in a debugger that displays current state, action payload, next state. It really does make tracking down state changes a matter of reading a global log.

Furthermore, because redux is not dependent on react and under the hood it is simply and event emitter, it becomes relatively easy to use the same exact business logic for one web app and use it for some other delivery.

We did this at my last company: because our business logic was based on redux and completely separate from the UI layer: we were able to build: a cli, chrome extension, outlook plugin, and mobile apps using the same exact business logic.


> Redux is not great for simple projects, it is great for medium and large scale projects.

I'd say that the only times I've seen Redux work effectively at all is when the project was small enough that the complexity remained manageable.

> > All of a sudden something stops working because someone removes a component that is dispatching on a timed interval etc.

> That's the problem: react and redux are not enough for large projects, you also need a way to manage side-effects. Incorporating `redux-saga` would fit that purpose.

I don't need a way to manage side-effects, if I don't use Redux...

I'll admit I haven't used Redux-Saga, but you'll excuse me being skeptical that introducing more complex tools will solve my complexity problem.

> We did this at my last company: because our business logic was based on redux and completely separate from the UI layer: we were able to build: a cli, chrome extension, outlook plugin, and mobile apps using the same exact business logic.

Again, this is not unique to Redux. It's perfectly possible to have your business logic completely separate from the UI layer without Redux. In fact, my experience is that Redux tends to cause devs to mix UI logic into business logic (and any sufficiently complex UI will have its own state and logic separate from the business logic).


> but you'll excuse me being skeptical that introducing more complex tools will solve my complexity problem

I'm a consultant and in my experience this misconception is by far the most common source of problems in redux projects. Redux is a very small and simple thing so you have to build a framework around it. Even redux-thunk isn't enough - that's only 5 lines of code.

I wouldn't recommend react/redux for public facing sites if there's no experienced, pure frontend team. A more batteries-included kind of framework would be better. There's a lot of thinking to do and hardcore levels of scaffolding to maintain before writing anything useful and maintainable with redux. But it can absolutely lead to maintainable applications.

Also, I've never seen any homegrown "vanilla" frameworks or data stores work well as complexity increases. It usually ends up as spaghetti, especially with a growing team + growing business demands. Or best case a poor re-invention of the wheel. There must be brilliant counter examples but they're probably rare, I may never have the pleasure of working with one.


Hi, I'm a Redux maintainer.

FWIW, we've got a new Redux Starter kit package that tries to be a bit more "batteries included". It includes utilities that help simplify several common use cases, including store setup, defining reducers, immutable update logic, and even creating entire "slices" of state automatically. It also includes `redux-thunk` built in, as well as some middleware that check for things like mutations.

Please try it out and let us know what you think!

https://redux-starter-kit.js.org


Thanks, this is incredibly useful, I use everything in this package! It also doesn't deviate from the spirit of Redux or abstract too much, like rematch for example. Without something like this, I find that many people structure their entire Redux code based on simple tutorials. They typically only read the docs or worry about best practices and complexity after they encounter problems. This kit will have them start off on the right foot.

Exactly!

I understand why folks have opted to create higher-level frameworks around Redux like Rematch, and it's not "wrong" that they've done so. But, looking at Rematch code, you can't really tell that it's actually Redux underneath.

With RSK, I've aimed for an intermediate level - decreasing the amount of things you have to write by hand and the literal number of keystrokes you have to type, but preserving the idea of "dispatching actions" and using reducers.

Glad to hear that you think it looks good! If you've got any additional feedback or suggestions, please let me know.


Re: long-term maintenance

So far every way of doing UI I have seen isn't maintainable long term. Yet somehow things wind up being maintained even if it is in that "why me?" kind of way.

I think this says less about frameworks/libraries themselves and more about the amount and sources of entropy present in the front-end. That's really what we're dealing with here.

Libraries/tools/patterns/frameworks all usually have the function of containing some of that entropy. In theory the best tool contains the most entropy while allowing you to produce results you can sell to all stakeholders.

I think over the years we are doing better and better, but it's a long game. We're not all the way there yet, is it even possible to get all the way to the dream?


> The issue with Redux is that it encourages side effects in components.

Which is why a lot of people that encourage Redux tend to also encourage one or more of the "side effect" managers such as thunks, sagas, or observables (my preference).


Why use a tool to solve a problem with another tool, rather than using tools that don't have the problem in the first place?

Because I decided I like React? :P

From my perspective, React is the thing with the problem: it doesn't have great state management for complex tasks / multi-component coordination. What I want to use is something like RxJS to manage such interactions and state, because it gives me a lot of power/control in a relatively easy way. One of the best options out there that I've seen is redux-observable, and thus Redux itself is just the "stuff inside the oreo" gluing React to all my interesting "epics" describing high level functionality in the applications.

It's also the Unix philosophy thing of use tools that "do one thing well" and then chain them together. React does view components rather well, Redux does state management rather well, Redux-Observable does state "interaction" rather well. Chained together they work remarkably well.


Plenty of people pair RxJS with React, including PayPal and Netflix. There is nothing precluding you from doing so. What kind of point is this?

Netflix is one of the contributors to redux-observable as well.

Sure, you don't need Redux in the middle of the "oreo", but it's also not the "wrong" answer, either.


Have you tried MobX? If yes - could you share your criticism?

I liked it more than redux, because you can have have simple class implementation and side effects without much hassle. Also TS support and testing is easy.


I have not tried MobX. It smells a bit too much like Aurelia, and I've been burnt a bit by Aurelia. More generally, too, things that make heavy use of ES2015 Proxies for side effects tend to make me pause, simply by nature of black/gray boxing those side effects, and also making it a little harder to control/throttle them in cases where performance matters more than "magic".

(Which is an interesting turn of events, personally, because I really liked Knockout ages ago, but its attempted successors in MobX, Aurelia, and even Vue leave me cold. I think partly because Knockout was so much more verbose and forced/needed a clearer "MVVM" separation simply by how "dumb" it was, whereas Proxies and Descriptors gives too much of an illusion that you are working with "plain" objects that don't need a clear "MVVM" separation until it is sometimes too late to fix a maintainability/tech debt hole.)


> From my perspective, React is the thing with the problem: it doesn't have great state management for complex tasks / multi-component coordination. What I want to use is something like RxJS to manage such interactions and state, because it gives me a lot of power/control in a relatively easy way. One of the best options out there that I've seen is redux-observable, and thus Redux itself is just the "stuff inside the oreo" gluing React to all my interesting "epics" describing high level functionality in the applications.

The observer pattern is mentioned in the Gang of Four Book[1], published in 1994. JavaScript first appeared in 1995. Observers predate Redux. You don't need Redux to use observers, and in fact there's nothing about React that is incompatible with RxJS.

> It's also the Unix philosophy thing of use tools that "do one thing well" and then chain them together. React does view components rather well, Redux does state management rather well, Redux-Observable does state "interaction" rather well. Chained together they work remarkably well.

Don't sully UNIX philosophy by comparing it to Redux! UNIX is such a different environment from JS space that it's hard to really even compare the two, but at the very least I think we can agree that "Doing one thing well" in UNIX means not creating a bunch of new problems that you need other tools to solve.

[1] https://www.amazon.com/Design-Patterns-Object-Oriented-Addis...


> The observer pattern is mentioned in the Gang of Four Book[1], published in 1994. JavaScript first appeared in 1995. Observers predate Redux. You don't need Redux to use observers, and in fact there's nothing about React that is incompatible with RxJS.

Yes, and before I was using React+Redux+Redux-Observable I was using Cycle.JS and everything was RxJS and/or Xstream (an RxJS-like) observable-based patterns.

As I said, this stack is a useful "oreo" for my needs right now. I understand if "oreo" isn't your cookie of choice.

> at the very least I think we can agree that "Doing one thing well" in UNIX means not creating a bunch of new problems that you need other tools to solve.

Again, I think the problem here is that we are disagreeing on what the problems even are. Again, I don't think these tools "create problems", I believe they solve very specific problems, and yes very "unix" in that way of solving as specific a problem as they can and no larger, and leave other problems that already existed untouched, whether or not they were in play, because again that's the philosophy here. React is "just" a view layer with a bare modicum of state responsibility. Redux is "just" a state layer. Redux-observable is "just" a tool for handling state side-effects. They don't need to solve every development problem, this isn't Angular. Similarly, they aren't the only tools for the job. There are several alternatives to each part of that stack (as others in this thread keep pointing out), this is just the one I've chosen for my projects right now.


What "state side-effects" are you dealing with?

The obvious and most common is asynchronous state that has some associated loading process/time. Especially those situations where loading some top level object implies to start loading a collection of lower level objects.

Reacting to object changes (persisting them to a database, or otherwise audit logging them).

Kicking off and managing "background tasks" like chron-job equivalents (5 minutes after a state update do some other related thing, such as a automatic state machine transitions), database synchronization/replication processes, cross-checking/merging in data from GPS/geolocation/compass streams, etc.


The problem that you end up with past a certain scale in a component-based app without a state management framework (third party or your own) is that you're performing business logic inside view components. By moving your business logic into your state management framework and using something like redux-saga that is designed specifically for managing complex asynchronous workflows, you can extract your application code from your views and make your views pure functions of the state tree.

When I hear someone complaining about redux using global state, I like to ask them what makes global state bad. The answer is usually that it allows any part of the application to change a value, which makes debugging difficult. This doesn't apply to redux and similar frameworks because every slice of the state can only be managed by a single, pure function, which makes it incredibly easy to debug. Additionally, redux uses a copy on write mechanism, so your state tree isn't actually being mutated, which allows you to use equality comparison instead of a deep compare to see what state has changed. That, combined with the fact that all actions go through a central dispatcher that is easily audited means unit testing your state transitions is almost laughably trivial. And since you are pulling all of your business logic out of your UI components, you can avoid the side-effect hell of unit testing your UI.

Having said that, I won't use react or redux for any website that doesn't have a heavily interactive UI with complex state that must be shared across many pages. Managing application state in your front end is an enormous burden and you'd be crazy to take it on without a need for it.


> The problem that you end up with past a certain scale in a component-based app without a state management framework (third party or your own) is that you're performing business logic inside view components.

I respectfully disagree here. All UI views in React can be controlled via parameters. Very few components in a React application require state management. You can add parameter functions to handle various events as well.

> which allows you to use equality comparison instead of a deep compare to see what state has changed

You are doing a lot of deep compares on state in a real world application? Why? If you only use parameters for the state of your component, everything is already handled by React out of the box.

> every slice of the state can only be managed by a single, pure function

Really? You can trigger reducers from literally anywhere in your application. Not only that, you can create multiple reducers to handle each action type. I've seen a situation with 24(yup, 24) reducer functions for a single action type. Many of those reducers contained complex business logic checking the overall state of the application. Then you have 2 or 3 action functions all with different business logic for that one type. Race conditions everywhere. setTimeout 0, here we go again. Step debugger hell. Of course, you should never do this, but in the real world, this is what happens over and over again.

> means unit testing your state transitions is almost laughably trivial

If you use parameters for state of a component it is 1,000 times easier. Because a component's view is not coupled to the global state of your application. Pass it parameters, test that it looks correct. Change a parameter, check if it is correct. Dead simple. Your tests are not bound to global state at all. Again, you started with an anti-pattern of managing state in child components, and now, instead of not doing the anti-pattern, you are adding yet another tool to fix it. Instead of just not doing it.

In summary, what you are describing is the "theory" of why Redux and associated tools should work. In every case that I've seen(10+ at this point) that has not happened. Not because Redux is a bad tool. Its not. But in the real world, it has become incredibly expensive for many organizations to maintain.


> Very few components in a React application require state management.

I agree. My apps usually consist of a few stateful components for dropdowns and modals and such with the remaining being functional components. The problem is the majority of "legacy" react apps I've come across seem to have the opposite ratio (I personally think this is because most react tutorials are written for fresh out of bootcamp developers by slightly more experienced fresh out of bootcamp developers).

> You are doing a lot of deep compares on state in a real world application?

Not a lot, but when you need it you really need it (usually for shouldComponentUpdate, but most recently I needed it for synchronizing state to localStorage).

> I've seen a situation with 24(yup, 24) reducer functions for a single action type.

You're right, that is insane. I personally use thunks or sagas to dispatch multiple actions that are specific to the domain model being updated and never update multiple slices of the state tree with a single action. For example, the action dispatched by clicking the sign in button should not update the user profile and the navigation state. Again, the problem in your example is not redux, it's a lack of separation of concerns.

> Become a components view is not coupled to the global state of your application.

The state of your application has to go somewhere, and if you are creating a small amount of stateful components and a lot of functional components, you are doing a lot of prop drilling, and every time the stateful component is updated the entire component tree gets re-rendered. If you keep the stateful components at the minimum height necessary, your business logic will be split up according to where it needs to be used instead of logically grouped by feature.

> summary, what you are describing is the "theory" of why Redux and associated tools should work.

You are arguing that redux is a poor choice because bad developers write bad code. I'm saying that the constraints that redux imposes on the structure of your code makes it easier to enforce separation of concerns as the app scales in complexity. The things about redux that most people complain about are the things that make it work so well in complex applications. I have seen unmaintainable apps that used redux, and equally unmaintainable apps that used component state. I don't think anyone can accurately say that one is worse than the other in a pathological case. At this point we're just arguing about opinions, but I maintain that explicit structure using shared conventions is still better than ad-hoc structure that requires institutional knowledge to navigate, even in the hands of untrained code monkeys.

One thing I have noticed is that every time react or redux comes up on HN it starts a flame war with the same arguments rehashed over and over, and when I get involved in these discussions none of my comments ever get any up or downvotes, which tells me that nobody is reading this and we should get back to work. :)


Great points all around. One question though — how many apps actually need to share state across pages? Seems like mobile apps have this problem more than desktop apps, because their screens are small and so the UI must be split into pages. Whereas a large monitor can support an expansive UI that isn’t “split up”. So if you’re making a desktop app, what would you use instead of redux? Seems like your points about splitting off business logic, debugging and testing all still apply when the state is confined to a single heavily interactive screen with complex state.

If you don't have any routing to deal with, component state is all you need. You can still move your business logic out of the view components and use lifecycle methods and event handlers to coordinate it, but the use case you are describing is the ideal case for vanilla react.

If making global state accessible is all you need Redux for, then I don't see why that state shouldn't be: 1) persisted to a back-end and re-fetched on route 2) Persisted to localStorage

If there some kind of state that doesn't neatly fit into these solutions? I know that passing around signed-in user objects is one popular use case for Redux, but in my opinion that could be easily placed into localStorage, or assigned to a window.global_state variable.


> persisted to a back-end and re-fetched on route

This is a huge pain in the ass and requires a ton of really tricky UX design. What happens when the data is cached and you fetch it again? Do you disable the UI and show a spinner until the request is complete (why bother caching the data in the first place)? Do you allow the user to continue making changes while the request is pending and try to reconcile conflicts when the payload is parsed (this problem is far beyond the skill level of most developers)? When the data is loaded, do you just change the content out from under the user or do you write a series of complex animated transitions to make it less jarring?

Updating state on every transition is hard, and keeping two copies of the data is also hard (cache invalidation!), which is why you shouldn't use an SPA framework unless you absolutely require it.

> If there some kind of state that doesn't neatly fit into these solutions?

The type of state is completely orthogonal to whether redux solves more problems than it creates. It should not be included by default on every project, and there are thousands of alternatives that might be a better fit. The heuristic for whether you should reach for something like redux is the size and complexity of your app, not the type of data you have. If your app consists of a single route without a lot of branches in your view tree and most of your components are only used once, you definitely don't need a state management library. Once you start adding multiple pages and lots of component reuse, something like redux starts to increase structure and maintainability at the cost of additional complexity. There is also a lot to be said for using an architecture that most of the react community is already familiar with so new developers can ramp up quickly.

> Persisted to localStorage

This is a standard practice, but you have to be careful not to spam localStorage with updates since it's significantly more expensive than in-memory object creation. I haven't profiled it but I wouldn't be surprised if it were several orders of magnitude slower. I sync the application state to localStorage in all of my apps, but I debounce it by 500ms and use equality comparison to prevent writes when no changes have been made. Obviously none of this has anything to do with redux, but redux's copy on write mechanism makes comparing states trivial, and any code that mutates the state trees requires an expensive and tricky deep comparison that negates the benefit of making the comparison in the first place (especially in the case of shouldComponentUpdate).

> assigned to a window.global_state variable

This is not the same as globally available redux state. For one, redux does all of the plumbing for subscribing to state changes and preventing unnecessary re-renders. You could spend a couple of days writing your own, buggier implementation, but why would you? Secondly, as I've argued elsewhere in the comments, the redux state tree doesn't have the aspects of global variables that make them such a dangerous anti-pattern. Writes are isolated to a single function, and all other references are read only, and it uses a synchronous message passing system with a central dispatcher that is trivial to audit. Another commenter complained about race conditions, but redux core is only designed to support synchronous operations, and there are well tested and widely used tools for managing complex, multi-step asynchronous state updates. If you have race conditions you are using the wrong tool for the job.

This is a bit off the topic of your original questions, but every time one of these redux conversations comes up there is so much vitriol from people who just absolutely hate redux for some reason, and almost every time every reason they give for why redux is a cancer is a well known anti-pattern. I guess they tried redux, hated the verbosity and saw botched implementations by other developers unfamiliar with redux, and decided that redux was the problem instead of lack of experience.

"The framework has to be idiot proof" doesn't really hold water for me, since I would love to see a react stack that scales in complexity to hundreds of components and dozens of routes that isn't horribly complex and deadly in the wrong hands. The root cause is that react is a view library, not a framework, and there is no standard architecture to provide a common language between teams and developers. Since every project is unique there is no knowledge base of best practices that aggregates over years like rails or django or laravel. A massively complex SPA _absolutely requires_ a strong, experienced lead to enforce good practices and maintainable architecture. If you have a free for all with a bunch of junior and mid-level devs you are going to get a pile of crap no matter what stack you use.

I am not a zealous redux partisan, I just prefer to work with it because I know it well and I believe it uses a pattern that scales well by keeping business logic isolated and broken up into small pieces. I'd be perfectly happy to recommend something like mobX. The only thing I'm strongly against is mixing application state with view state. Anyway, I've spent several hours and put a lot of thought into responding to questions on this thread and some of the comments have been pretty rude, frankly (not yours). I would like it if people could discuss this topic politely and constructively, and not go into it with their mind already made up and ready to do battle with anyone that disagrees with them.

Rant over :)


Thanks for the time and effort you've put into this thread, it has been very interesting reading your comments, which have a lot of content and a lot of experience behind them. I wanted to ask you about this because I've been reading about when to use Redux and when not to, and I had basically come to appreciate that it would be helpful for the kind of app that I'm working on daily. That app is very complex and very dynamic, but because it is a desktop app there isn't a lot of routing since I can fit a whole lot on one screen. When there is routing, it's usually to another view with enough complexity and code for a totally separate SPA.

So like I said, I've basically decided that Redux would be a great benefit for maintaining a consistent, easily debugged architecture for an app of this complexity, but then I came across several people talking about shared global state across routes as a good heuristic for knowing when Redux is appropriate. As mentioned, I don't really have that in my own app, so I was a bit confused by this and wanted to get some more details from you. I think you've cleared it up pretty well.

I'm completely in agreement with you about the likely source of dislike and complaining for Redux. Absolutely people jump to it too often when it isn't necessary. More generally speaking, I think there's a default attitude that front-end should be easy, and then people are rudely surprised when they find out that it's actually very hard. Distributed systems problems, cache invalidation problems, combinatorial scaling of complexity with every feature and source of user interaction... you already know this. They blame the team or the tool, but there's a fundamental complexity there that's unavoidable and deserves respect.

Anyway, thanks again, I've enjoyed reading your opinions on this.


> attitude that front-end should be easy, and then people are rudely surprised when they find out that it's actually very hard. Distributed systems problems, cache invalidation problems, combinatorial scaling of complexity with every feature and source of user interaction...

This sums it up so succinctly I'm going to borrow this next time I'm discussing react with one of my C# teammates. :)

If you want to chat more my email address is in my profile.


1. You're conflating a bunch of terms here, but I think you're referring to global application state changes being treated as a pure function which takes in the global state and event parameters, and returns a new global state. There's nothing stopping you from doing that without Redux; the state = function(state, event) pattern is supported by native JavaScript. If that's not what you're talking about, please clarify.

2. This is only marginally more powerful than a debugger.

3. I would consider this allowing you to shoot yourself in the foot. Explicit is better than implicit, and explicitly defining your dependency tree is a benefit, not a downside. When you're feel the small pain of having to explicitly define a data dependency, that prevents you from introducing it if you don't have to, thereby avoiding the much larger pain of having an overly complex dependency graph. By adding Redux you're adding hours of debugging time on complex global dependencies to save yourself a few seconds worth of keystrokes.


As an addendum to #3, it's a single state that is passed down as a global/app state. If you break it up with the context api, it can get messy quickly.

As to other comments about logic in the View or State, it's bound to happen... the two aren't actually divisive concerns. Personally, I'm happier to use Redux than seeing prop drilling everywhere.


What are some "costs" you think it has?

Redux definitely adds an extra layer of complexity to a project and a lot more boilerplate. That is what lead to Dan's famous blog post "You Might Not Need Redux" from 2016.

https://medium.com/@dan_abramov/you-might-not-need-redux-be4...


Thinking of Redux as a 'detached state tree' that the whole app can subscribe too might give a better picture of some problems that it is solving. In React, when you lift state up and up, you mostly end up tracking lot of irrelevant state in the top most component which kind of weirdly manages lot of state just for their children. There are some genuine use cases of Redux by tracking the whole 'app state' in a detached way, safely update/transform them (with pure functions) and more importantly you could just subscribe for necessary data at any level. Context API is helpful, yes, but Redux (or MObX or any state management tool) is still helpful when done right.

> In React, when you lift state up and up, you mostly end up tracking lot of irrelevant state in the top most component which kind of weirdly manages lot of state just for their children.

I'm not sure why you think the data is irrelevant, or why the component manages it "weirdly".

I'll point out that these top components actually share a lot in common with Redux, except that they can be duplicated and composed with other components, if for example you decide to drop your top component inside of a larger application, and the toplevel components actually don't end up managing data they don't have to (LESS "irrelevant" data than Redux, perhaps?).


> I'm not sure why you think the data is irrelevant

I believe the GP meant "unrelated". Can you drop your top level component into another application with different children and still have it work? Can you move the child components to another view tree and still have them work? It seems like what you are describing is a top level component that is tightly coupled to its descendants with too many responsibilities. In the ideal react app architecture you should be able to take any component and move it anywhere else in the app and it should Just Work. This is the problem redux is supposed to solve, and I would argue that by enforcing an explicit pattern that most experienced react developers know, you will get closer to that ideal than if you have a variety of home grown solutions that vary from project to project (and even from developer to developer on the same project). "The Tyranny of Structurelessness" etc etc.


> Can you drop your top level component into another application with different children and still have it work?

Yes, it's a matter of passing the child into the parent as a prop.

> Can you move the child components to another view tree and still have them work?

Yes, this sort of thing is exactly what you get for free by doing things the way I describe.

> In the ideal react app architecture you should be able to take any component and move it anywhere else in the app and it should Just Work.

This is exactly not what happens in Redux projects in my experience.


> This is exactly not what happens in Redux projects in my experience.

Sorry to beat this dead horse, but how does redux, which binds data directly at the level of the component that displays the data, make portable components more difficult than vanilla react where stateful components and functional components are tightly coupled? Do you have links to a gist or something so I can see what you're describing?


I have to let you in on a big secret. State has always been global. Have you ever worked on an application backed by an RDBMS? Redux simply moves state. It doesn’t expose it any more than a database.

I've found that explaining Redux as an in-memory database/ORM helps a lot of colleagues get over the hump of what Redux is for and why people often feel a need for it.

I'm surprised you dislike Redux simply because it's a form of global state.

Sure, global variables make debugging difficult when you don't know which function changed them where and when and why. But that doesn't happen if you keep your functions pure and only make changes from within reducers – at least that's my experience.

(Boilerplate, yes, Redux adds that. But at least it's all in one place, and not scattered throughout your app.)


> Sure, global variables make debugging difficult when you don't know which function changed them where and when and why. But that doesn't happen if you keep your functions pure and only make changes from within reducers – at least that's my experience.

Sticking to reducers IS a good idea and it does make things a bit better. The problem with global state goes deeper than that, though.

Often, as you learn about the structure of the data, it becomes useful to change how the data is structured and stored. In global state, you can change that in reducers, sure, but then all the places that render that data have to be updated. You don't have the option to represent the same data in different ways that might be more suitable for different parts of the application. You either have to change them all at once, or synchronize a bunch of states that really contain the same data (which is even worse).

With independent components, you do spend some time synchronizing data across components, but each component has the option of how to represent its data internally, so the effects of changing data representation in one area are usually very local, and each area of the code gets to represent the data in a way that's reasonable for what it's doing.

I'll also add that with independent components, you sometimes get components whose only real job is to manage data. That's actually sort of like a Redux! But you can spin up multiples of them without having to manage an array, and compose them or even nest them without issues.

> (Boilerplate, yes, Redux adds that. But at least it's all in one place, and not scattered throughout your app.)

To be clear, I don't really care about boilerplate. It's easy to generate that stuff, but even if you write it by hand it's faster than debugging implicit, hidden complexity. Boilerplate ISN'T the problem with Redux, as far as I'm concerned.


If you're giving me the choice between dealing with this:

> Often, as you learn about the structure of the data, it becomes useful to change how the data is structured and stored. In global state, you can change that in reducers, sure, but then all the places that render that data have to be updated. You don't have the option to represent the same data in different ways that might be more suitable for different parts of the application. You either have to change them all at once, or synchronize a bunch of states that really contain the same data (which is even worse).

or this:

> With independent components, you do spend some time synchronizing data across components

I'm not even hesitating before I choose the first option. My editor, static analysis, and the mystical art of the function can give me all sorts of help with the first problem. Good luck with those sync bugs.


You selectively quoted me, ignoring where I explained that synchronization isn't as big of a problem with passing properties into components. I already addressed your concern. Don't selectively quote me, it's rude and just shows you aren't following the conversation.

Futher, Redux doesn't solve synchronization issues in situations where you can't represent the data the same way. In the most complicated situations, it actually exacerbates the issue because it separates the data from the components that use it, making static analysis tools unable to see how your data changes might break the components. This also goes to show you didn't even understand the part of what I said that you selectively quoted, since I already said this.

> I'm not even hesitating before I choose the first option.

Perhaps if you hesitated a bit more, you could use that time to read all of the options and understand them.


> Futher, Redux doesn't solve synchronization issues in situations where you can't represent the data the same way.

I would argue that synchronizing data between multiple representations is an anti-pattern, and the exact anti-pattern that redux, with its emphasis on a single source of truth, was designed to solve. Synchronizing state is almost always going to lead to hard to diagnose bugs in edge cases. There's even a blog post on why it's a bad idea on the official react blog [0]

My solution to this problem is to use computed values generated by a library with memoization like reselect. I structure my data as close as possible to the API data models and use selectors to transform the models into the data structures that disparate UI components require. If you need to change your UI component, you don't need to refactor your store, and if you need to change your store structure, you don't need to refactor your UI components.

[0]: https://reactjs.org/blog/2018/06/07/you-probably-dont-need-d...


I read the thread. You hand-waved away a non-trivial problem by "explaining" properties are a thing. Thanks, bud. I'm sorry I didn't cite your favorite source to your satisfaction, but I quoted the relevant parts of the post I replied to.

> Futher, Redux doesn't solve synchronization issues in situations where you can't represent the data the same way.

It's kind of the whole Redux philosophy that you won't do that. It's in the FAQ. There's no "can't". You're never forced to keep duplicate data in your store.


But, in a project of any significant complexity, you will represent the data in different formats, because transforming data into different formats is one of the main functions of software. Relying on a framework that assumes you won't do something that you will do is a Very Bad Idea.

It's almost like `mapStateToProps` is a thing and Dan Abramov has built a web app before. You have to store and transform your data in a normalized form, but you can consume it however you want.

Restrictions are the price of solving hard problems (even if you don't want to admit they're hard) in a deterministic fashion.


It's generally considered a best practice to use pure selector functions in your UI components so the only place in your application that references the actual data structure is the root selector that pulls data out of the state tree. I personally try to structure my selectors so that any refactoring only requires changing a single line of code.

Okay, so the only way it's actually possible to have any refactoring of your data structures require only changing one selector is that you've got a single selector for literally every piece of data in your system, at which point you've had to manually flatten everything out into a bunch of selectors, and lost all the benefits of being able to read a structured chunk of data. If you actually do that (which I don't think most projects do fastidiously) you're creating a lot of boilerplate, again to solve a problem which was created because you decided to use global state in the first place.

I'm not saying there aren't solutions to the problems I'm bringing up. I'm saying you don't have to solve them in the first place if you don't bring in Redux.


Not at all; you can write selectors that return a branch of your state tree, and you can generally tell where the line should be (user makes more sense than userName and userEmail).

You keep saying that you won't have these problems if you don't use redux, but I am arguing that _you do have these problems_, you're just creating ad-hoc solutions for everything that you would use redux for, except those solutions are sprinkled into your UI components in a way that makes them full of mutable state that is impossible to test and a constant source of bugs. Note that I have already agreed that there is a scale where redux is overkill and creates more problems than it solves. Once your app has a few dozen components it's time to start thinking about another layer of abstraction.


> Not at all; you can write selectors that return a branch of your state tree, and you can generally tell where the line should be (user makes more sense than userName and userEmail).

And then you're right back to any component that uses User being tightly coupled to the structure of the User, without any of the syntactic cues that allow you and your static tooling to connect the two.

> except those solutions are sprinkled into your UI components in a way that makes them full of mutable state that is impossible to test and a constant source of bugs.

That's not the case:

1. There's nothing preventing you from treating components as a pure function of their props.

2. At the top level, it's necessary to have some mutable state, but I'm not sure where you get the idea that this isn't testable. Redux doesn't remove mutable state: all redux is doing is a big complicated version of newState = pureFunction(oldState) which is perfectly possible to do using Vanilla JS functions.


One of the problems I noticed with Redux is that you need to clean your state. This is one of the reasons why global variables are a problem.

If you keep your state in a component, you don't need any housekeeping, once the component is gone, the state is gone.

This is not true with Redux. You have to keep remembering to clean the state after you're done with something or you're going to introduce a bunch of bugs.


Anecdotical comment: While studying computer science, I almost fail a test because I used global variables. Since then I avoid them like the plage, and I get rashes when I see them.

And I thank my teacher for knocking the bad habit out of me. So when I see global variables beyond the initialization of core objects, I take it as a bad code smell.


Global variables are different from global state. Every program has global state, whether you like it or not. Global variables are a poor way to declare, mutate, and read global state.

Redux means everything is global state which is terrible. A grid I render now has to have global state and most projects forget to do any cleanup - so you end up with all this junk in redux that isn't needed anymore, clogging up memory.

Nothing is forcing you to put everything in Redux. If state only has relevance to a single component then keep it in that components state, Redux works perfectly fine with this approach.

And when the state has relevance to two components? Now it's okay to make it a global, because we can't be bothered to type "prop = value"?

I'm just not buying this argument. People add Redux to projects because they intend to use it, and there's almost never a case where a piece of data is actually needed in enough places that it should be global. It's certainly not common enough to justify importing a whole framework for managing global state.


> Every program has global state

Could you explain what you mean by this?

My intuition here is that what you're saying is true in a trivial sense, but that most state CAN BE (and should be) local if you're breaking your programs into reasonable building blocks.


You have information which has global nature, used in multiple sorts of the application. This could be, among other things - STDIN/STDOUT/STDERR file handles - static configuration - some parts of runtime configuration - application info (in a game maybe current score, current level, active players, ...)

All that information exists only once and is needed in many parts.


>exists only once and is needed in many parts.

I think many people could argue that this concept itself is a bit misguided. There are plenty of application patterns and architectures that help you move stateful data around your app and translate it for the components who need to consume it or change it, while hiding it from components in the tree which do not interact with or care about the state.

If you have many different components in your app that all need access to the same state data, and they exist at different levels in the hierarchy, maybe you need to re-think your component structure rather than figure out a way to inject mutable global state everywhere?


Sorry to reply twice to the same comment, but if you have an instance of a user model, and you need to display the model data in the navigation bar, on the user profile page, and in a comment thread, how would you manage that data? And do you think that having a single source of truth reduces complexity or creates more problems than it solves?

There are definitely options and choices for all of this, but I can give my professional opinion.

First question (show user data in nav bar, user details page, and "comment thread"):

User profile page is obviously showing full user details, so you're going to want to have a separate endpoint for "getUserDetailsByUserId(int userId)" or however you want to name it.

What data are you showing in your nav bar? Is this just a user-avatar image link/button? You would rarely want to display anything other than an avatar and/or username in a navigation bar. You could maybe talk about a navigation drawer instead, where you have more simple details like maybe email address and phone number or something.

What about the "comment thread"? Are you showing anything more than an avatar and/or username? This sounds like the same use-case as the nav bar... how would the display differ here?

If you have use-cases for anything more than your basic "user avatar" and "full user profile," (and maaaybe "user basic info," for a "nav drawer" or something, although those are being phased out of most current design standards) then I would seriously urge you to re-think your app design. That polish of showing the user info in a slightly different slice on some specific page is almost never going to pay off for your company, imo.

Anyways, if you want to be naive about all of this, you just save the userId (and token or whatever, but that should be in your http middleware) after a new login session, and then you request separate "getUserNavBarInfo(userId)", "getUserDetails(userId)", and "getUserCommentInfo(userId)" and load the results of those into your UI views on-demand. If you need to progressively tune/cache your API, you do this separately based on usage stats for each of these 3 use-cases, you don't start with directly caching "Users" and adding the business logic client-side to translate into the 3 use-cases.

If you want to do a more thorough dependency-injection "user component," then this might vary depending on your DI framework, but the high-level idea would always just be to create a user module with all the info needed for a given user, wire it up to reload the module in your DI graph on new login and on-success of any request to update user info. You could have both your "login" and "update user" endpoints both return the full set of data needed for the "user module" on success. Then you need to set up your DI injection component scoping so that your user info injection component is dumped on user logout and settings change, and is recreated to do it's injections with the new/updated user module each time. A singleton DI "user component" that you must choose to inject into any UI component that wants to show user information seems much more constrained in complexity to me than just having the ability to arbitrarily pull out various bits of user info from a global redux state, at any place in your app.

Second question (single source of truth, increases or decreases complexity?):

I think this question is orthogonal to the capabilities Redux (and similar) provides. Redux has nothing to do with outright increases or decreases in app complexity, it is simply a tool that enables various (opinionated) architecture patterns. If you have a separate, domain-specific, well-defined event+data architecture that you are sticking to very strictly to keep a handle on complexity, then Redux can (imo) reduce boilerplate and allow very elegant interactions between various data/biz logic/UI components of your application, all without any "tight coupling". It's really just a message-bus pattern at some level. This sort of thing has been around longer than the concept of software itself, there are hardware components literally called "buses" that basically do the exact same thing (ship events and data around to various interested parties without requiring a direct circuit connection). The danger is that it opens up a TON of pathways to insane complexity and totally unintuitive event & data flows, because it kind of allows you to arbitrarily add "side effects" to basically anything in your application. VERY easy to foot-gun yourself here if you start getting lazy and just wiring up random shit instead of following strict event/data patterns and keeping the "feature code" as simple as possible (e.g. with a strict facade for writing new pages).

This might rustle some feathers on here, but I wish people would think of React/Redux sort of as "framework primitives" that are SUPER useful for constructing your own domain-specific client-app frameworks, but somewhat dangerous to open up directly to front-line product code written by junior devs. I would much rather see a few senior devs use React/Redux to construct a tightly-defined domain framework that exposes a simple facade to junior devs to construct new pages/routes/behaviors in your FE application. I think using these tools like this would greatly reduce the dreaded "React learning curve" of 3-4 months that everyone talks about. That could be done over time if you put in the work up front to build an internal facade pattern around your core React/Redux app architecture. Then junior devs could choose to dig into things behind the scenes as they go, instead of being forced to front-load the entire React/Redux knowledge stack up front right when they walk in the door.


Redux state isn't mutable. Mutating the state tree in a redux reducer is a bug.

Okay, technically it's copy on write, but I think if you put a bit of effort into understanding what people mean, you're smart enough to understand what the parent comment meant. Let's avoid making this holy war into a semantic argument. :)

Okay, I think we're talking about different things. I don't think of stdin/stdout/stderr or static configuration as state because they don't change. Typically when I talk about state, I'm talking about mutable data that may change over the lifetime of a program.

stdin/stdout/stderr may be redirected during the lifetime of a program. The OS manages them and they are "reference pointers" (file handles) for multiple reasons.

Also, "state" does not necessarily imply "mutable". (Redux encourages an immutable state approach where good reducers don't mutate state in place, but instead build new state from old, though Redux is not strict in enforcing this best practice. For Redux the "current state" is "file handle" that simply updates from one object to the next, not all that different from stdin/stdout/stderr or even somewhat to static configuration that is somewhat updateable without restarting the application.)


> stdin/stdout/stderr may be redirected during the lifetime of a program. The OS manages them and they are "reference pointers" (file handles) for multiple reasons.

> Also, "state" does not necessarily imply "mutable".

Okay, sure. I'd rather not get into a semantic argument about the meaning of the word "state". Suffice it to say that I'm talking about mutable global state.


Like the state of the logged-in user.

I think these debates about global variables or state could be much more specific, though.

For example, we tend to realize that letting any component access a `require('./store').currentUser` singleton may make testing harder, but this global dependency still exists when, say, it's distributed to all components through the React context. I reckon most people are thinking of the singleton example when they lambast Redux but it certainly doesn't have to be that way.


I don't think Redux is that big of a deal as you describe it.

Many people just use setState.

Since my last Redux project in 2015, I did many React and React-Native projects and not one of them used Redux.


You've been lucky then. I've worked on a few teams (I'm a freelancer) and even when they didn't add Redux, it's been something I've had to argue against.

sounds bad.

I only did green-field projects where I was the only front-end dev.


Redux was the solution to server side rendering state.

If you don't use redux, then keeping state synced with a server side rendered application because nearly impossible.


> Redux was the solution to server side rendering state.

Could you explain what you mean by "server side rendering state"?


Server side rendering mounts your application in the server and sends down html along with an initial state.

The client receives this initial state and uses it with the html to glue together a working UI on the client.

This removes the massive JS bloat into raw html and split JS for each component.

Instead of sending 3MB of JS, you send only the JS needed to render the current page... and send additional JS as a user navigates through your website.

Here's an example with Create React App: https://github.com/cereallarceny/cra-ssr


Okay, but that's an even worse idea than what I've seen Redux used for. Now you're splitting the UI between client and server in a completely custom way, that adds even more complexity. Worse, the performance is likely to be worse because now you're paying the bulk JS load cost of loading Redux AND the latency cost of loading small parts as you go: the worst of both worlds. I doubt this is what the Redux folks had in mind, but if it was, it's even worse than I thought.

>because now you're paying the bulk JS load cost of loading Redux

Gonna have to quantify that. Cause I imagine if you did, you'd redact that statement. Redux is a very straightforwards and SMALL library that handles global state.

Its concept can be difficult to follow at first which may cause some to think it way more complex under the hood than it really is.


> you're paying the bulk JS load cost of loading Redux

Redux is small.

> the latency cost of loading small parts as you go

The components are static JS split into files.

Pop those into a CDN and you get the best of both worlds.


Redux is tiny. And with HTTP2 it's better to send multiple small resources than one large payload, especially when it's JS which will lock up when parsing.

> Then introduce Redux and similar frameworks, and I totally lost interest. It's as if the entire React community forgot all the lessons they learned writing Python and C programs in college and went back to creating global state. What in the actual hell?

Fair point. But could it be possible that there are lots of people doing React that never went to college and never wrote Python or C programs?


That's true, and possibly the source of the problem.

Or people who went to college but not for Computer Science.

I went from MVC style all-in-one frameworks (Rails, Laravel) to application APIs fronted by single page applications and hope the developer mindshare tilts back to MVC frameworks. Something that'd take me an hour or two in Rails can take a week using these new tools, even after being reasonably experienced with them. Don't even get me started on Apollo (not my thing at all, and from my experience most don't know how to use it well, including myself).

Most apps are fine serving html, using plain old boring forms, and having the odd React or Vue component where necessary to do some heavy lifting for user interactions. Moreover, it's a lot quicker as a small team to iterate.


I hope we don't go back to MVC for everything. I think we just have to use the right tool for the job. If an app is highly interactive or will have frequent data updates, or if it's supposed to be used almost like a native app, a SPA is the perfect way to achieve this. If it's going to be like most sites, traditional MVC will probably be better.

Not that react isn't great for traditional websites, I've just seen too many fullstack or backend devs struggle with it, so if they're going to be involved in the frontend it may be worth considering the alternatives.


SPA isn't automatically the best solution for a page or site with frequent updates.

The updates are handled by JavaScript and http calls.

You can write a lot of that stuff in a dozen lines of JQuery with nicely refreshing content and ajax instead of throwing in large amounts of framework bloat.


> You can write a lot of that stuff in a dozen lines of JQuery with nicely refreshing content and ajax instead of throwing in large amounts of framework bloat.

OTOH jquery is much bigger than you'd expect, there isn't much of a difference between a minimized jquery and vue, or even react once you factored in gzip.

And while I've no experience doing so using vue, writing small dynamic react components embedded in larger static HTML pages is quite enjoyable.


It's 2019, most of the stuff that jQuery used to handle is now included in the browser API. For instance, to have "AJAX", simply try window.fetch instead of $.get.

Then add a polyfill per api call to support anything but the most recent browsers, if you happen to want your site useable by people with old systems or who are at work.

...which you can selectively serve only to the old browsers :)

That sounds trivial.

jQuery 2.1.3 is 27.8Kb. React + React DOM is 35.6Kb. 7.9Kb extra isn't nothing, but it's not something many sites really need to stress over. It's definitely not enough to state using React is adding "large amounts of framework bloat".

I'm not talking about the bloat of the framework itself but the code you write to use the framework.

When you have 2mb worth of "React code" and the framework itself only takes up 35.6kb, that's a lot of bloat.


2mb is a LOT of code, like an absurd amount for most projects. That almost always points to larger issues, like a complete disregard for bundle size in the first place.

And if the project isn't worrying about bundle size at all, then even their vanilla/jquery page is going to end up bloating a ton as well.

More often than not the culprit in 2mb bundle sizes is a a few packages that include "data" in the bundle (For example, i've seen timezone and locale information bloat bundles by megabytes, and in one case a 5mb bundle ended up being 4.6mb of zip codes...)


Yeah, that was me, sorry. I wasn't given a choice.

lol I did it too once! We were making a PoC one time for a small app, and ended up needing a way to quickly determine some location information related to the zip. I remembered that I saw the ~5mb bundle once that had all the zipcodes in it, and found a library that would let me do that, and bundled it right in.

The PoC ended up working out, and we built the infra to correctly handle the lookups without needing to bundle the entire country from there, but man did that raise some eyebrows from a few other devs that noticed it!


Having used the internet for 25 years I can confidently say most React apps are far smaller than most jQuery apps, mainly because jQuery apps didn't use compilers or bundlers. Hell, most didn't even use minifiers.

Even ignoring that, React app sizes are getting better. Modern React apps (basically since 16.7) that are written with things like Suspense, lazy, and hooks are usually pretty small. Writing functional components and composing your app pushes you to write less code. Plus React gets things like code splitting for free with webpack if you use lazy, so the first page load only downloads things that are actually needed to get to interactive.

No doubt some less considerate developers will still manage to write giant apps that take ages to get started, but they don't have to. Bloated apps are a function of developer's choices rather than React (or any other JS framework) forcing the apps to be bloated.


> Modern React apps (basically since 16.7) that are written with things like Suspense, lazy, and hooks are usually pretty small.

Come on, 16.7 was released in December and 16.8, with stable Hooks, was last week! It's interesting that React has added these features and it bodes well for the future but you can't claim capabilities that have only existed for the a few months is what constitutes "modern." React's pace of adoption has been remarkable but that also means there's a lot of code that already exists that isn't going to be changed right away to take advantage of these features.


These features existed in the form of 3rd party libraries like react-loadable for code splitting and recompose for hooks. I don't know any serious React devs who haven't used code splitting in the past few years, and recompose was very popular as well. We just have a canonical way of doing these things now.

> Modern React apps (basically since 16.7)

So like, a month ago?


Didn't you know?

If it isn't less than a month old, it's "the old way" :)


If you have 2mb of "react bloat" you wouldn't have "a dozen lines of jquery".

I recently started a hobby project and initially went with a JS solution. But when I had to start deciding on auth, maybe an orm, routing, db layer, and templating, I said fuck it and installed Rails.

Previously I had never built a real product in Rails, only the book store tutorial. I'm really happy with Rails so far. I don't have to worry about a lot of shit I had to worry about in JS land and now I can focus on the app itself.


As you're doing Rails I recommend you check out Stimulus JS (https://stimulusjs.org/). I've installed it in a recently project (Rails 6, rake webpacker:install:stimulus) and it's like a breath of fresh air. Totally gets out of your way, but lets you add behaviour to your app as you need it.

Agreed. Stimulus has been great and very refreshing. I love writing my html using erb templates, and being able to do that and easily add client side interactivity has been great!

This is my experience as well. Sometimes the conventions are frustrating, and particular to Rails I still don't know how to handle the front end well aside from jQuery (how are you doing it? Stimulus + Turbolinks, or...?), but is it ever refreshing to just focus on your product instead of all the tooling surrounding developing your product.

If you need a lot of JS, Vue is a nice choice. You can drop it in for just a single page of your site if you need heavy JS on one part but still want Rails on the rest. Or you can go full-on Vue front end with Rails in API mode, or anywhere between.

If you're starting from scratch, you ought to check out Elixir. Phoenix is a supremely productive framework.

For a component here and there React is a pretty bad choice because of its size. Svelte could be a more suitable option, but I’m not so sure it passes the magpie test.

In my experience this is the use case where vue shines. It's far easier to drop it into an existing html template than to create a react application for a single component.

Magpie test? I couldn't find an answer on google.

The article has a reference and link to [1], where the behavior of constantly looking for new and shiny tech is likened to that of a magpie. As Svelte is still fairly new and not widely used, I think maybe it is in that class of technology.

1: https://blog.codinghorror.com/the-magpie-developer/


Makes sense, thanks!

I feel as if many sites that used to be fine and work well have regressed in usability and features and introduced unexpected behaviors and bugs since the SPA paradigm seems to have taken over. This seems especially true for many corporate, bank, shopping brand sites, etc. An example is the Capital One 360, Chase, and AMEX sites and even Reddit.

Even JustWatch.com seems like it's fairly polished, still has it's quirks. So, I just end up using InstantWatcher.com instead. Hacker News works well as is too, except the search on the bottom can act up it seems once in a while.

Edit: How could I forget, Netflix. The UI, getting to the details of a show/movie. Browsing, discovery, searching, it all feels broken and unintuitive. The DVD site last I checked was still decent. Netflix seems like the poster child for usability and regression issues moving to a SPA.


Fellow JustWatcher here, care to elaborate which quirks exactly you mean? Back when SPAs were still pretty new, we took the bet to make one with a pretty large surface area and despite a lot of issues (SEO especially) so far we're pretty happy with that decision.

Infinite scroll, showing the details, clicking back sometimes doesn't bring me back to where I left off. Same when scrolling horizontally for example on the New releases I'll have to start scrolling right again after click on the details.

Honestly, your website is probably the best implementation of a SPA website with multiple pages I have ever seen I can recollect. It still has quirks though. I just don't see why you would want to make a website like this a SPA.

Does that help a little? I wrote this quick, off the top of my head. I can try and provide more details maybe in an email or some other communication means too.


Hey, that's super helpful, thanks!

Why SPA? Well, a good question indeed. Actually, we're cross-compiling the same code for the webapp onto iOS and Android targets with build flags, where we're leveraging more platform features (i.e. geolocate cinemas).

Also, it lets us make the experience itself much more snappy once you're on the page, as there's just content to be re-loaded. You can switch tabs, we can remember scroll positions, stuff like this.

Stay tuned though for our completely rewritten release based on very recent technology, I'm hopeful this will change your perception about SPAs on large sites coming in March!


> Stay tuned though for our completely rewritten release based on very recent technology

Nothing can possibli go wrong


TIL there is a search on HN after more than 6 years of browsing...never noticed it

For CRUD apps, using Rails etc. with Turbolinks[1] is the best way to go IMO. It gives you the SPA feel without the headache. In all SPAs, we load JSON, with Turbolinks, we load HTML of that page alone (without the CSS, JS etc).

[1] https://github.com/turbolinks/turbolinks


this is not just one simple drop in replacement, well it is if you load only html, but pages are usually html + js, even for "old" mvc. so because there is no page relaod you have to rethink all your events, objects and so on.

so if i have to rewrite my js with this just so i could fake SPA then benefits are so much smaller


Take a look at Stimulus JS in conjunction with TurboLinks

https://stimulusjs.org/handbook/origin


If you are talking about events for $(document).ready type things -- there is a turbolinks event for page:load -- it's a copy/paste replacement.

The rewrite is often just replacing document ready with a different event.

Compare this with rewriting your app as an SPA.


Can you use Turbolinks with a Java backend?


It is the best way to do what ? because from what I understand turbolink is giving you nothing. The only thing you can have is activating a a loaderbar at the top of the page ...

Turbolink is a crutch for people that are not able to server side render an html in a few milliseconds.


It's giving you more than nothing.

It's fetching and replacing the HTML that needs to be changed, but removes the need to do a full-page reload, so the browser doesn't have to re-load and re-parse all of the HTML, and JS, and CSS. Even though the browser will keep a lot of this stuff cached, Turbolinks can make a site feel a lot faster from a user's perspective. But regardless, it's more than just a loading bar at the top of the screen.

Whether it's the right fit or not depends a lot on what you're trying to do.


I don't use Elixir/Phoenix, but Phoenix's LiveViews brings all the butter to the monolith bread. State remains on the server, only visual state is sent over websockets, and the HTML is transformed with morphDOM.

https://dockyard.com/blog/2018/12/12/phoenix-liveview-intera...

I hope to see this idea brought to Rails, but the its websocket story doesn't seem there yet.


It's a combination of the websocket story and the server side HTML story that make this possible.

HTML rendering with Phoenix is lightning fast. https://www.bignerdranch.com/blog/elixir-and-io-lists-part-2...


I agree - it seems like a LiveView equivalent for Rails should be doable in principle. Check out these two projects, they're sorta heading in that direction: Fie: https://fie.eranpeer.co/ AnyCable: https://anycable.io/

If you watch Chris Mccord's videos (the creator of Phoenix and LiveView), it was an attempt to build a similar system for Rails that drove him to create Phoenix. The Ruby/Rails concurrency model mean that he was patching over so many cracks to try and get it to work, and it never quite did.

We turned to React as the UI solution in our Rails app almost 2 years ago. It was the hot thing and I fell in love with the concept of components. While it did work well, I regret the decision. It convoluted our codebase and it seemed like simple tasks took way longer than I estimated. We're now back to doing things the "Rails way" with erb templates, turboklinks, and Stimulus to give us that JS functionality we were looking for when we chose to start using React. It's been a breath of fresh air.

I've started a new project with Rails 6 and Stimulus just recently. Stimiulus really does feel like a breath of fresh air. Just enough to let me do what I need to do without feeling like a burden.

Personally I was dumbfounded by complexity of doing async things in redux. Libraries like redux-thunk, redux-sage, redux-observable should not exist. The amount of boilerplate required was incredible and meaningful typescript support was very difficult to achieve.

Then I tried mobx, I was able to write a small app after 15 minutes of reading the docs and now I love react.


Yup, MobX has made developing more complex React components / UIs a sane endeavor once more. Every time I use MobX, I think to myself that it can't possibly be this simple...then run the code, and pick up my jaw from the floor because everything just worked the way you intuitively thought it should.

Meanwhile, relying on setState alone for complex components ends up being very error prone and tedious. I still rarely use MobX for global state because I prefer the original appeal of React in terms of making modular, reusable components, but I often use MobX as the state mechanism for my more complex components and bypass having to rely on setState altogether for those components.


With context api and hooks you don't need redux or mobx.

Not that either one was really all that necessary in the first place anyway.


I've still found the concept of computed properties in mobx to be extremely useful (and I say this as someone who relies on regular React + SetState 90% of the times). MobX encourages you to think about representing your state in the minimal possible representation and to heavily use computed properties that depend on this smallest, irreducible state representation for everything else. Switching to this mindset makes developing more complex components (especially UI/forms) a breeze. I also find MobX to be great for async things and much easier to handle than via setState. Using setState alone in these types of complex components ends up being really tedious and prone to errors (largely driven by the async nature of setState updates).

My experience as well, MobX saved React for me, and I did a 180 from hating it to loving it.

For me, there wasn't even an alternative library needed.

I mostly use setState nowadays and it's enough.


As a developer I agree that developers should prefer to get features out quickly and optimize the experience later. However, as a user, I think this section is really important:

I’d like to try and make it work offline. To do that, and do it well, you need a way to show the data in different ways even when you can’t call a server.

I often have "What the hell is this thing doing" moments as a web app hangs trying to complete a round trip over my mobile connection when I know it has already fetched the information on that page or I know it could be doing something useful despite not being able to connect.

The author is not proclaiming that SPAs are a bad idea. He's just pointing out how much extra work they are, and that some types of apps are worse as SPAs, or simply much harder with nothing to show for it. He even points out that not all the badness of SPAs is intrinsic to being an SPA:

Why does a website that orders food from restaurants need a Megabyte of javascript?

I tried to figure that out by inspecting the API calls. It turned out they were tracking every mouse event.

In short: 1) horses for courses, and 2) SPA apps are a lot more work and you have to decide when the benefits are meaningful. Less contentious but maybe less fun than trying to argue which is the one to rule them all.


There is a place for SPAs. I just built a single page React app (using the create-react-app package) that mostly replaced a complex pile of spreadsheets. It came out fantastic, I think. The entire compressed Javascript is about 150 kilobytes, the scripts typically load in less than 500 milliseconds, and my co-workers are very happy. The code is easy to change and the interface between the client and server is clean. (Note: I disabled the built-in PWA features; they made versioning difficult due to excessive caching.)

On the other hand, I also maintain a public facing service that is mostly server-rendered with lots of JQuery snippets. I don't see a need to convert it to a SPA. It works well as-is.

I conclude from my experience that public facing services probably shouldn't be SPAs, while things that outgrow spreadsheets might be good candidates for SPAs. I wonder what other areas have been explored.


> It beats being a Magpie Developer. I have more time time to pet my dog, read a lot of books, make fresh pasta by hand, and circle a more slowly evolving collection of powerful technologies that let’s me get stuff done without spending half my free time chasing shiny new things.

Saying stuff like this is sure to please the hacker-news hipsters. But... is this honestly anyone's experiencing using new web technologies?

I tend to be on the bleeding edge of tech, and I very rarely regret learning a new technology. And I do not feel like I am wasting all of my time flitting from technology to technology.

I just think this is a smarmy attitude disguised as wisdom. People should like what they like. And as someone who has had to climb that hill before: Waiting around not expecting the world to change around you is a losing bet every time.

The fool doth think he is wise, but the wise man knows himself to be a fool.


> I just think this is a smarmy attitude disguised as wisdom

> The fool doth think he is wise, but the wise man knows himself to be a fool.

I fear that this wasn't meant to be ironic.


Another angle is that "SPAs" are build on top of a fragile and anti-engineering tech stack: JS, CSS, HTML.

In the past a 'SPAs' was build on top of more solid foundation like smalltalk or later Delphi. Most issues is that the browser stack, put it in real terms, is not the "right tool for the job" and will never will, without serious re-engineering.


Could you provide some links/keywords about these alternative solutions? This sounds very interesting but I don't know were to start.

Is unclear to me if you talk about Delphi and smalltalk?

I am interested in designs/technologies that could be viewed as alternatives to the usual tech stack for SPAs, even if these technologies are outdated but exhibit interesting properties compared to what we are used to today. That would include Smalltalk and Delphi yes. Sorry if I misunderstood your initial comment.

Well, Delphi is well alive and current:

https://www.embarcadero.com/products/delphi

(it have a free edition) and alzo exist Lazarus, a open source clone:

https://www.lazarus-ide.org

Is probably the most fleshed idea under more "traditional" paradigms (OOP, RAD, etc)

Smalltalk and others are less popular(?) and only know them passing, so can't give too much of that.

---

Another interesting stuff can be rebel/red:

https://www.red-lang.org

much low-level but nice way to do UIs in a apparent declarative way..


Thank you!

I come across so many sites that have been needlessly built as SPAs, and so many of those are broken in ways that are really hard to understand even as a technically savvy user. For regular people, it's a truly appalling experience - the sites my wife has to use for work are all like this, all broken and all slow - she blames her laptop. SPAs need to die.

Isn't this just the same as saying bad code acts badly though?

People can, and have written bad websites using every technology. I can think of plenty of badly written, hard to use MVC websites from my past.

It should come as no surprise, that bad developers have found ways to make badly written SPAs as well today.

I don't think we should judge a technology by its worst implementations.


I don't think it is, no. A plain old HTML and CSS website gives me some clues about what's happening when I click things: if I click and nothing happens I can see a progress bar in my browser that shows me that I'm waiting on network - if I do the same in a SPA I get no feedback at all. You could say that all SPA developers should be writing this feedback, but even that isn't reliable - quite often the broken SPAs _do_ show their own feedback with a spinner or similar, but still there's no way of knowing if it's actually doing something or if it's broken. I can open the web inspector and look for XHR requests, but if it's trying to do something with no XHR then again, no way of knowing. They break user expectations, and when they don't function correctly this can be hugely frustrating.

Oh, and I forgot to mention that they often break standards that a lot of people rely on, in particular the native zoom in browsers.

Writing good SPAs is exponentially harder than good non-SPAs. At least from my experience.

Web 3.0 is the internet of race conditions and hangs.
More

Applications are open for YC Summer 2019

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: