Then some bunch of geniuses decided it would be awesome to put everything together in the name of components. Today, you open facebook, the creators of React - normal drop-down with just a list of barely 5-6 items is a fucking component that makes 10 different requests. I would even argue this unnecessary forced interactivity is what perhaps annoyed users the most as everything always has to "load" with a spinner to the point of the platform being unusable.
Same goes for instagram. It's not just that, React is a hot ball of mess. It's not opinionated, so anyone can use anything to do anything. This means if you work with multiple teams, each one uses their own code organisation, state management library and general coding paradigm. Eventually the engineers leave and the new guy decides to do things his own way. I've honestly never seen a company with a great product run over React. Everything always is being re-written, migrated every 3 weeks or straight up is buggy or doesn't work.
React is the worst thing to happen to the Javascript ecosystem. The idea is good, but the execution is just piss poor. I mean look at Vue and Svelte, they managed to do it right.
> Today, you open facebook, the creators of React - normal drop-down with just a list of barely 5-6 items is a fucking component that makes 10 different requests. I would even argue this unnecessary forced interactivity is what perhaps annoyed users the most as everything always has to "load" with a spinner to the point of the platform being unusable.
That's a design decision, though. Sure, your point is basically that React is not opinionated enough and allows you to do anything. But in the same way you could criticize JavaScript or Python because they allow you to do "anything" and some people write shitty code.
As a previously big React dev I agree 100%. If anyone feels this way please spend some time on doing Sveltekit project (e.g. rewrite a personal React project).
It's a breath of fresh air.
I don't know about the other UIs, but on the web, some things impinge on the model you (and Redux) are proposing.
One thing is: you, in the gamedev world, have the luxury of having a frame buffer to write to. You fully control what gets rendered. Unfortunately, React and its cousins all have to deal with the idiosyncracies of the legacy browser environment. You have CSS, which applies and cascades styles to elements and their children in often non-obvious ways, and is a monster to deal with on any given day.
In addition to CSS, you have multiple potential sources of state. Every HTML slider, dropdown, input field, accordion, radio button, checkbox has its own browser-native state. You have to control for that.
On top of all of this, the browser application is usually just a frontend client that has to interact with a backend server, with asynchronous calls that require wait-state and failure-state management.
One thing that's in common with all of the above problems is: they're localized. All of these things I'm describing are specific to the rendering layer and therefore the component layer; they are not related to central state. A central state trying to capture all of these problems will fail, because component state has to be wrangled locally near where the HTML is; CSS also is component-level; and the network states are often very closely related to each component. If we maintain a central "game state", the data complexity just proliferates endlessly for each instance of the component.
So, the default these days is to keep state very close to each component, including network state, and often business logic also gets sucked into the mix. I try to avoid putting business logic in components, but people do it all the time unfortunately. But it does add to the complexity.
In other words, there is -real- complexity here, stemming from the fact that the web was never built to be a distribution+execution layer for rich applications, but evolved to become exactly that. It's not just bad application architecture or bad decisions by React maintainers.
Maybe I'm wrong, since I'm not a game developer and don't see what you're seeing on your side.
What I still don't understand is why the browser is that way in the first place, and why all of the native, not-browser GUI frameworks that people use are also that way. People opt into using React Native, even! But the regular run-of-the-mill frameworks that are widely used for native applications are also annoyingly complex to work with, so much so that I've repurposed my engine for when I want to create native applications and have been working on building a desktop UI framework within it that follows the same model I use for games (albeit nowhere near production-grade, just covering "the cases I need").
> the browser application is usually just a frontend client that has to interact with a backend server
I will note that this is a constraint that is shared with gamedev. Most multiplayer and even many singleplayer games these days are server-based.
Then computers got faster, much much faster. It became possible to redraw the whole UI from state every frame without it being a significant cost.
At the same time retained user interfaces managed to become more and more costly to do just about anything. I don't think for any particular reason other than computers were fast and they didn't need to do much better.
I find it really odd that there are user interfaces that take longer to rearrange their items than it takes for the same CPU to RayTrace a scene covering the same amount of screen area.
This bottleneck could be alleviated if browsers shipped native dom morphing or even some kind of native vdom but we're stuck with userland js solutions.
To an extent this is how react works internally. There is a function which takes state and produces UI. In order not to have to re-render the whole UI if only a small part of the state changes, there is a diffing algorithm and "virtual dom" that is diffed against. Maybe it doesn't work exactly like that anymore but that's the gist of it.
I can't really think of a statement that resonates with me less.
What you are describing is exactly what GP complained about: "state as something distinct from both the UI and the data source".
React can be 100% stateless, functional, and have the state live somewhere else. You just need to apply the same limitations as your model: components should be simple and not store data in themselves.
This is why people came up with things like Flux/Redux/Reducers/Immutability, to handle this in a standardized way, but nothing is necessary.
That is a ”controlled component” model which is bad for interactivity, especially text inputs.
If every keypress triggers a state change and rerender, the UI will be slow and things like focus management become complex issues.
Without a rerender, it must now use a reactive binding to update the field value.
If you don’t want to update state on every keypress, your component must be uncontrolled, store its state internally (in the DOM) and update it to a parent store e.g. when the user stops typing (debounced) or moves focus out of the field. These are not trivial things either, and as a result, components get more boilerplate to handle the UX complexity. And of course, there are now UX pitfalls.
Indeed, these are reasons why reactive patterns exist. Now, if they just managed to abstract away the tedium.
"just" is doing a lot of heavy lifting here. Where do you store "pure" GUI state (button state, is expandable expanded, …)? Do you really want to setup Redux for this? (And no, the DOM is not an option in non-trivial cases.)
Moving state out of HTML and into JS means we now have to walk this ridiculous tightrope walk trying to force state changes back into the DOM and our styles to keep everything in sync.
Given that problem, reactivity isn't the worst solution in my opinion. It tries to automate that syncing problem with tooling and convention, usually declaratively.
If I had to do it all again though, DOM would still be the source of truth and any custom components in JS would always be working with DOM directly. Custom elements are a great fit for that approach if you stick to using them for basic lifecycle hooks, events, and attribute getters/setters.
I recall the property passing model being a nasty abstraction breaker. HTML attributes are all strings, so if you wanted to pass objects or functions to children you had to do that via “props” instead of “attributes.”
I also recall the tag names of web components being a pain. Always need a dash, always need to be registered.
None of these problems broke it; they just made it irritating by comparison. There wasn’t really much upside either. No real performance gain or superior feature, and you got fewer features and a smaller ecosystem.
Even so, Lit is widely used to build very complex apps (Beaker, as you know, Photoshop, Reddit, Home Assistant, Microsoft App Store, SpaceX things, ...).
Property bindings are just as ergonomic as attributes with the .foo= syntax, and tag name declaration has rarely come up as a big friction point, especially with the declarative @customElement() decorator. The rest is indeed like a faster less proprietary React in many ways.
That's an ok choice in some cases, but the web clearly moved on from that to be able to have richer interaction, and in a lot of cases, much easier development.
My usual go-to rule is that business logic belongs where the state lives - almost always on the back end for state of any real complexity.
With true web apps like Figma I consider those entirely different use cases. They're really building what amounts to a native app that leverage the web as a distribution platform, it has nothing to do with HTML at all really.
I'm sure you could find counterexamples so that isn't a hard line I'm proposing, but it is my opinion that nearly all website or web app built today over uses client state.
Model knows nothing about controller or views, so they're independently testable. Models and views are composed of a tree of entities (model) and components (views). Controller is the glue. Also, API calls are done by the controller.
So it is more of an Entity-Boundary-Control pattern.
Meanwhile, those of us that were building web apps with JQuery and other tools prior to React know just how painful "web development without reactivity" actually was.
Also, things like unidrectional data flow are generally considered normal now, but back in that era it was rare. Two-way binding was much more popular, with constant bugs as the app grew. Around 2013 or so I was trying to switch a new page we were building to a very simple form of unidirectional data flow to deal with constant issues (ours issues were mostly losing state, we were all ad-hoc and not using two-way binding) and the other devs just did not at all understand it, constantly sidestepping it without even thinking because jquery made it so easy to touch everything.
I've always maintained that no reactivity is a much simpler mental model. Mithril and Imba do this with better than good enough performance.
I think Remix 3 will be following this approach too.
The previous Remix was rebranded into React Router. Remix 3 will not use React and will apparently not use reactivity either.
There was a presentation last year:
Instead of HTML, think about GTK or Swing.
To add React-style "reactivity" to it, instead of just making a dialog to change the "title" of a document and committing the change when you press OK, you'd need a top-level "App" class that holds all the state, a class for state properties with IDs accessible at runtime which probably would be a variant (accepts any primitive type), a binding class to bind the toolkit's textbox to the App's state "title" property (because you'll probably want to bind a lot of textboxes, so it's easier to separate the code into classes), and then every time the user types something into the textbox, instead of using the toolkit's code that is already written for you which updates the textbox' state directly, you block the state change in an event handler, send the state change to the App class, let the App class figure out the differences between the current state and the new state, and then it calls some callback in the binding class that is responsible for actually changing the text in the textbox to reflect the new App state. You'll probably run into a ton of issues (selections resetting, assistive technologies bugging, etc.) that you'll have to deal with externally somehow. All just to make it do exactly the same thing it would have done anyway.
It's like you have a fully autonomous robot and you want to add marionette strings to make it move.
And then said developer does what they think feels right: "I have my state and I simply want all the fields to reflect my state". So they try and rewrite the component into some sort of mini immediate-mode style component. All of the event handlers get wired up a single "layoutComponent" method that tries to call all the UI component setters based on the current state with all the problems you alluded to. I know I've done this type of things numerous times before going back all the way to my first internship, well before React was even a thing.
I think modern frameworks solve the reactivity issue this well enough, that it really doesn't matter if the underlying framework is not natively reactive. I will say though that I've primarily used Vue.js where most state is relatively local and we don't try to re-render the world on every input. I think part of the problem with modern dev is likely that React has become the default instead of a simpler framework like Vue.
Ironically, in most cases events are only used by one object, but you always want to consider the possibility that two objects will want to observe the same event, so now you need an entire event dispatching class, and then you'll want observable properties, and the nail on the coffin is going to be observable lists. When you reach that point, one event triggers another, which changes a property, triggering another event, and so on and so on. You are 5 layers deep into event callbacks. The call tree just has the same "callCallbacks()" method over and over again.
Bugs start happening because of the order in which callbacks are called becomes important, so now you need a way to give some callbacks priority over others, or make them happen after all normal callbacks were called. One callback destroys an object which has callback on the event that destroyed it, so you're going to need a wrapper around your callbacks that gets notified when callback's object is destroyed to change its reference to null in order to avoid executing code on the destroyed object if this happens while iterating the callbacks in the event dispatcher. Sometimes calling callbacks in wrong order is a performance hit, when it doesn't just get stuck into an infinite loop and you run out of stack.
I wonder if there is GUI programming paradigm that solves all of this or that you can call the "best" one. Maybe it's reactivity, maybe not. Who knows.
UI elements automatically reacting to data changes (as oppposed to components updating themselves by listening to events)
That's not so much a lack of statefulness as it is making zero effort to lift your application's data model out of platform-specific UI concerns.Is there really a difference? Angular uses RxJS in a pub-sub scheme. (At least it did when I last used it.)
But yes, React is a mess. JSX was the original sin of mixing HTML inside JS. And those bundlers and tree-shaking at build time? Ugh.
What if you had this instead: https://community.qbix.com/t/loading-at-runtime-the-web-fram...
That of course led to developers building much more complex UIs. Which offset the gains from reactivity. Hence the mess and we're basically where we started.
Maybe focus on a use-case? Something like, "No-build, no-NPM, SSR-first JavaScript framework specializing in Time-to-interactive" - maybe?
React is not popular simply because engineers hate themselves or enjoy pain. There are problems it solves, and problems it creates. Explain what problems your solution solves, and feel free to dunk on React while you're at it, but write a tagline like this and I'm not gonna take you seriously.
Anyway, interesting approach for up to medium pages (not apps!). Totally not replacement for react.
There's nothing wrong with either of these if used correctly. Thus "hate" is a rather shallow argument.
In order to do the JS that I have to do with an SSR app I went with Alpine.js. It reduces the JS I have to write and that fits my SSR approach.
It feels a bit like a modern jQuery to be honest: you cannot build whole apps with it, but just to sprinkle on top of an SSR it does really well.
[0]: https://github.com/statelyai/xstate?tab=readme-ov-file#super...
You can build similar things with Alpine/htmx, but once things grow, you end up reinventing structure. Qite just bakes that in from the start.
Most of the time, it's enough to build in a simple, clean, and lightweight way. Just like in the old days. Your server's resources will also thank you. Furthermore, the simplicity of web pages is also rewarded by search engines.
If it were up to me, I'd build sites exclusively in .md format :)
Oh my. If it works just like Ajax from >10-15 years ago, then I will be super happy. :D
And came to conclusion that after certain complexity of UI - React kind of components are unavoidable if you want to be able to reason about your code.
Think of Shopify admin panel with product variations each variation having different pictures and what not.
Not saying not doable in plain JS.
But then Chrome can be written in NASM too, C++ is just...
It's not a great language for it.
total: (c,v) => v > 1000
See the docs: https://qitejs.qount25.dev/States/Field-Matchers.htmlSee also: HTMX and possibly even jQuery
https://code.qount25.dev/qite/qite-js/src/branch/master/src/...
https://code.qount25.dev/qite/qite-js/src/branch/master/test...
I dislike react because it's long overstayed its welcome. The vast majority of react projects are bloated messes and it truly feels like the react community is being steered by dev influencers that have very little experience working on projects (this includes the react maintainers themselves IMO).
There are way better libraries to write maintainable code in (svelte, solid, and even vue is better FFS). There are other mental frameworks that allow for good engineering practices as well like htmx or hotwire.
React is only here for the same reason that Java Spring is here, it was one of the early adopters that has too much momentum where leadership across companies are actively hostile to devs so there's no time to actually create good stuff but rather stamp out garbage so billionaires can be slightly more rich.
I'll just stick with a $5 vps with lamp and jjquery