Hacker News new | ask | show | jobs
by m0meni 2686 days ago
React's model kind of feels like the holy grail of UI development to me (at least on web). Is there anything out there that you guys feel is superior? I'm not talking different frameworks like vue or angular, but rather UI paradigms on platforms that aren't web. People have been making UIs for desktop and mobile for a very long time now, and I'm curious how people have historically dealt with all the problems that React addresses, and moreover, how they deal with other problems like data-fetching, state-management, etc.
18 comments

React's model is very similar to how 3D applications work at a high-level. There is a render loop that is either on-demand or continuous, the latter is more common in 3D. During each iteration, input is collected, background processes are run like AI, etc. and they all change the state of the application's data. The new state is given to the rendering engine, and the rendering engine re-renders the entire scene as efficiently as possible.

It turns out it is a lot easier to program dynamic 3D scenes using this method, rather than trying to do two-way binding like Angular, JQuery, etc do. And the performance is typically better too. Imagine trying to do two-way binding in a AAA game with 1,000s or even 100,000s of individual objects in a scene. It would be a programming nightmare! Instead much of the effort is spent trying to reduce the amount work the GPU has to do when rendering the entire scene such as occlusion culling, distance-based level of detail, etc. React's virtual DOM renderer is also trying to render the scene (DOM) as efficiently as possible. But admittedly it is much simpler than Unreal Engine's renderer, but the high-level concept is similar.

I think this is why React feels so natural to so many people when building dynamic web UIs compared to JQuery, Angular, and even Vue.

Just to correct this a bit, while this is certainly true of AngularJS, this is certainly not true of Angular. Angular since v2 has taken a reactive approach throughout, and even the two-way data bing is just syntactic sugar for an evented pattern powered by rxjs. Perf-wise, other than initial load, Angular is actually a little better from my understanding & based on numbers I’ve seen.

React has certain weaknesses that aren’t seen in other UI libraries/frameworks as well - forms are a complete mess to work with, even with formik, and animations are pretty problematic.

As with anything, there are tradeoffs to approaches. FB isn’t as form heavy in general, so optimizing how it works for the rendering inputs from external sources & dev usability makes sense for their use cases. It’s important not to conflate this by overpraising.

> forms are a complete mess to work with

Could you elaborate on this? I've been creating form heavy react apps for a couple of years now and haven't really come across anything that would make it 'a mess'.

I find that the biggest issue with forms and react is attempting to use lifecycle methods and local state to manage the behavior of the controls: at work, I’ve done a bunch of refactorings to replace local state and lifecycle methods with redux and logic in the render method of the parent components, and this has always led to simpler components and has fixed a lot of bugs caused by inconsistencies between props and state.
I think this is because you are using both state and props to manage the values of fields. I generally tend to use only props, with an onChange handler passed in from the parent component. This way, I can always have an up to date mapping of field names to values in the parent component, while simplifying state management in the child.
This is exactly what I’m saying: use only props and handle state elsewhere.
You made not need redux! Found lot's of projects where they plug redux an turns the project a completly mess. (connected components everywhere), actions to manage local component ui state..
I’ve heard people are pretty happy with Formik.

https://jaredpalmer.com/formik/

I think redux is the only thing that can prevent a react project from becoming a mess: I’ve noticed that the major bug points in the app are where people try to use something else to manage state
I was with you until the past sentence, which seems unsubstantiated. VueJS, at least, uses a similar virtual dom rendering concept. I find Vue's API much more natural than React's, but that's unrelated to their internal implementations. Can you provide further detail?
Yes, I am aware Vue is more similar to React than the others. I probably shouldn't have said anything about Vue. Since I did, here we go.

There is another component to React which I didn't mention that gets inspiration from the 3D world: the API. When I first saw React's API, the first thing I thought was "that looks kinda like OpenSceneGraph, cool!" Now this is the very subjective part, having spent 8-9 years doing 3D graphics React felt natural to me. Given its popularity, I must not be the only one either. I am glad you like the Vue API but it doesn't feel like a 3D engine. For whatever reason, many people seem to prefer the 3D engine feel. On purely technical merits, I think React and Vue are basically the same. But I think there is some intangible difference in how the tools feel. Some people like React and some like Vue and both are right. However more people seem to like React.

> Now this is the very subjective part, having spent 8-9 years doing 3D graphics React felt natural to me. Given its popularity, I must not be the only one either. I am glad you like the Vue API but it doesn't feel like a 3D engine.

I would postulate that the subset of people who are both web developers and have also worked on 3D graphics is a relatively small slice, so I wouldn't be convinced that a 3D engine-like API is the reason for its popularity.

Correct, not directly. My point is that the 3D engine feel seems to have some sort of wider appeal even if you haven't done 3D engine development. It was direct for me because I am in that small slice. Like I said, this part is very subjective.
IMO Vue.js API is way messier than React's: https://news.ycombinator.com/item?id=17471199
Under the hood, Vue uses a similar virtual dom model as react, and at its core is based on one-way data binding. Vue's `v-model` is not a two-way binding a la angular, but syntactic sugar for the common (non-flux) react idiom of updating a parent's state based on an event emmitted by the child (which is handled by a vanilla react-style prop function)
I'm not sure I agree at all, 3d engines render loop foregoes any attempt to skip unnecessary rendering to focus on fast, continuous rendering.

React on the other hand tries as hard as possible to avoid rendering, in fact it's whole design of immutability isn't because functional style is better, it's just convenient for it's requirements to avoid rendering.

For me react is more of an antichrist of UI tech, as much as I use it and rely on it, the day I can just mutate some state and that renders (i.e. .. just straight up dom), the better.. if I want to then layer on some immutability patterns then that's entirely in my apps domain.

> 3d engines render loop foregoes any attempt to skip unnecessary rendering to focus on fast, continuous rendering.

3d engines often go to great lengths to avoid sending unnessesary data to the GPU. Frustum culling or more sophisticated occlusion culling are standard practices.

Have you looked at Mithril? Looks a lot like React, but there is no need for immutability, because it redraws after events or xhr calls. You can just mutate a model/store object in event handlers and the UI reflects the changes. Imho, this is a much simpler model and it's what you need 99% of the time.
OP is correct, the React render loop is very much inspired by 3D game engines: https://www.youtube.com/watch?v=x7cQ3mrcKaY#t=1196
3D engines have the part where they try to reduce rendering in the engine part, so you don’t deal with it when writing your application, but it’s definitely there.
When I say minimize rendering, I don't mean skipping frames although it could mean that. During a single frame, 3d engines try to minimize the number of triangles, textures, etc that need to be rendered in that frame. Also some non-realtime 3d applications, like CAD, will skip frames. If React has to do animation, then it can't skip frames either.
High performance 3D applications (like games) typically recreate the entire rendering command list from scratch each frame instead of manipulating an existing "scene graph".

React feels more like "retained mode rendering engines" which were popular in the 90's and early 2000's.

React provides an immediate mode API (virtual DOM, which is recreated from scratch on every render) implemented on top of a retained mode API (the actual DOM which is stateful).

Diffing and piecemeal updates are an implementation detail/optimization.

Diffing results in different behavior if components have internal state.
Makes me wonder what a web browser with an API like a graphics library (opengl, etc) would look like.
Wait a minute, react isn't great because they came up with some ground breaking new concept in ui programming. It's popular because it allows for component based design and updating only what it needs to by diffing. These aren't really novel concepts. It's just a good implementation of ideas that's really helped by mass adoption and the overall community converging on one particular framework leading to lots of tutorials, guides, etc.

Even before react, I had webapps where I'd cobbled together helper objects that did things pretty similar to react, although obviously not as robust.

I like React’s model a lot too and I agree it simplifies typical UI development tasks considerably. The main weakness of this approach in my experience is that is can make it hard to have detailed control of what happens when transitioning between states. Animation is maybe the most obvious example of this. You often need to distinguish between the transitory state of the animation and the underlying React state. I know some interesting work has been done all this already in React but it’s an inherent problem in all reactive approaches.
It's a mix of a lot of relatively good choices/trade-offs from the React team.

I've been doing GUI apps for long enough to have seen a few attempts in a variety of IDEs (and languages). I like React exactly for this reason - that it models what they've done with components, but in a way that is more robust and flexible. IDEs tend to come and go but JSX as a language seems to have grown beyond React. It's a relatively good way of describing UI that can be read and understood while leaving ample space for dynamic composability which has historically been an issue to represent in the IDE UI builders I've used. I've usually had to resort to mixing UI builders and own code, or giving up on the UI builder entirely and instantiate classes myself.

I like React because of the trade-offs. It's not perfect. It's just imperfect in some acceptable ways.

From my dabbling with QT's QML, I gather it would be a lot more concise than React for some use cases.
To me a "holy grail" wouldn't just be about being superior, but about being complete. Even within the web space, with its simplistic UIs, React doesn't do a lot (intentionally). Whether it's a shining diamond of mathematical beauty or a plug in the bunghole of the web stack doesn't matter in that regard. For a complete UI you need more, and then the bikeshedding starts.

And Desktop UI libraries tend to be even more complex. And as usual, warts are on the outside.

Native UI systems tend to support more complex event dispatch, which often involves cross-component communication -- look at drag and drop, for example, or the complex exclusion behavior of gesture recognizers on iOS. Carrying an interactive gesture through to an animation while preserving velocity is also difficult to do using the DOM.
Immediate Mode UIs, at least for "code driven UIs" (as opposed to artist-driven UIs):

https://caseymuratori.com/blog_0001

https://github.com/ocornut/imgui

Qt's QML is React with 1/3rd the bloat in terms of code
Yeah, I always tell people to look at QML when it comes to clean UI frameworks. It is a bit sad QML is not a web framework.
Any good examples?
Qt's QML is "1/3 in terms of code" only because it has the entire Qt framework behind it. On the web you have to reinvent the wheel for everything (because there are no wheels in the browser and its APIs).
I think he refers to the code you write.
React == Windows 3.1
This is actually a not entirely invalid description! There was a neat article a few years back that specifically compared Flux to a Win32 WndProc function:

https://www.bitquabit.com/post/the-more-things-change/

Prior discussion: https://news.ycombinator.com/item?id=10381015

Or pretty much any other MVC GUI framework, with modifications because it lives in the browser and renders to a DOM.

Certainly when I first saw it my thought was, "hey someone did Cocoa for the Browser, nice".

https://blog.metaobject.com/2018/12/uis-are-not-pure-functio...

"One way data flow" is pretty much exactly how MVC works, except that MVC decouples a bit more: the model is only allowed to send #changed notifications, the view then pulls what it needs. The data still only flows in one direction.

"Actions" in Redux are very much the "Command" pattern as used in C++ GUI frameworks such as PowerPlant.

Hmm I think the difference between a primarily imperative API like `addSubview` vs a primarily declarative one (“what’s the list of subviews at any given moment?”) is a pretty important differentiator. It has nothing to do with the browser DOM — it’s about the programming model. I tried to express that in the article but maybe I didn’t convey my point well enough.
> `addSubview`

That's been my revised working assumption, but it's almost completely unclear from your writings, and also comes from a fairly deep (but understandable!) misunderstanding of GUI frameworks.

addSubview is not a defining feature of most GUI frameworks. drawRect is.

addSubview is used once in construction, and then you're done. And a lot (if not most) of the time it is hidden, because you just load a GUI definition. For example in Cocoa, you define your GUI in Interface Builder. IB saves a nib/xib, which is an serialised object graph with parameters. You then load that nib and voilà, there's your GUI!

The GUI is fully static/declarative. It reacts to dynamic content by drawing it in its "drawRect" method.

So where does the misunderstanding come from? It comes from recent changes in how developers (ab-)use GUI frameworks. I haven't full grokked how this came about, but it seems to be part (a) widget toolkits (b) horrible drawing APIs and (c) the iPhone with LayerKit/CoreAnimation.

This change has been that for example, when there is just some dynamic text to draw, people have been using text-label widgets instead of just drawing the damn text in drawRect. So suddenly you have people constructing, adding and removing views at runtime as a matter of course, rather than as something done in exceptional circumstances, which I gather is what you (rightly) object to.

However, this is not the "programming model" of GUI frameworks, it is an abuse of those GUI frameworks. Which is why your idea that the difference is about programming model, while understandable and somewhat defensible, is ultimately mistaken.

To put it succinctly, people are "drawing with widgets", instead of drawing in drawRect: like they're supposed to. So instead of drawRect, they are using addSubview to draw. However, widgets were not meant as a medium for drawing, they were meant as mechanism for constructing the (mostly) static UI that then draws itself, including the dynamic parts. As it is not really the supported way, it is cumbersome and error-prone.

If you were to actually adapt the framework APIs to a "drawing with widgets" model, every view would have a "drawSubviews" method in addition to or in lieu of the "drawRect" method.

See also: UIs Are Not Pure Functions of the Model - React.js and Cocoa Side by Side

https://blog.metaobject.com/2018/12/uis-are-not-pure-functio...

There is also a deeper pattern there, which goes back all the way to the beginnings of computer graphics: the back-and-forth between "object-oriented" graphics (see GKS[1], PHIGS[2]) and immediate-mode graphics. (Note that this is not OO in the computer language sense, but in the computer graphics sense).

Everybody, it seems has this idea that it would be nice to have a declarative tree of your graphics (and it also happened historically as a result of display-lists for vector graphics). It would also be nice to have a reusable library/API for this. Enter GKS/PHIGS. But then it turns out that things don't quite match up, so you end up having to express your domain graphics as complex (sub-)trees. So you need to imperatively edit the shape tree/database. Which is complex, painful and error-prone. In the end, it becomes easier to just drop the entire shape database and re-create it from scratch every time. At which point the whole idea of a shape database becomes somewhat moot.

Enter immediate mode graphics. See OpenGL, Postscript, Quartz, etc.

However, drawing everything procedurally is cumbersome. So you add back structure and composable elements. So let's have them be domain-/application-specific, draw themselves in immediate mode and also handle interaction. We might call them "Views". What's neat about Views is that they straddle the "object-oriented" and "immediate" graphics divide, and you can decide yourself where you want to be. You can shift more to the object/widget side and use object-composition, or you can shift towards the immediate-mode side and use procedural drawing. Best of both worlds, at least in theory.

And then things happen that make people shift towards the object-graphics side (sucky graphics APIs, phone UIs etc.) and lo-and-behold, we have the same problems that we used to have with GKS/PHIGS! And then we propose the same solution (modulo environmental and accidental differences).

And round and round we go.

[1] https://en.wikipedia.org/wiki/Graphical_Kernel_System

[2] https://en.wikipedia.org/wiki/PHIGS

Ah ok I see what you mean. Well yeah, I’m talking about how it’s being used in practice.

drawRect is a primitive but once you start dealing with layout and text measurement I think it can get hairy and at that point you might end up with imperative subview soup again. Somehow people using React don’t fall into that.

drawRect is low level because it only specifies rendering. But UIs usually care about local state and when to destroy or create it. Especially in lists. That’s something I mention in the post which React has a solution for but I don’t think drawRect is sufficient for expressing this generally. See the ShoppingList reordering example.

> being used in practice.

And that's great. But then please argue/describe from practice, and not from some largely mythical fundamental differences in programming model that only confuse. That would be really helpful, thanks.

> layout and text measurement

Yup, as I mentioned, the text APIs in Cocoa/CocoaTouch/Quartz are so rancid that just slapping on a TextLabel is incredibly more convenient, despite the fact that you get horrible messy subview soup (I like that term, can I borrow it?).

The solution would probably be better text APIs. Which are actually not that hard to build.

https://github.com/mpw/DrawingContext

(Alas, the text stuff in particular is only partially complete, I had more important projects. The very rough idea is to be able to essentially printf() into a view)

> drawRect [..] only specifies rendering.

Yep.

> But UIs usually care about local state

Right, that's why drawRect is embedded into these things called Views, which have local state.

> Especially in lists.

Right. And you have easy-to-use Views like NSTableView that handle lists beautifully, without you having to worry about the active set of subviews. Essentially you give it a data source and it will ask the data source about what it needs, when it needs it. Meaning it can handle arbitrarily large/infinite lists without problems. There are layers of customizability, from just delivering data via specifying cells to customise drawing/interaction all the way to having the NSTableView use arbitrary subviews to represent rows/columns.

https://developer.apple.com/documentation/appkit/nstableview...

No new programming model required, just a view within the current programming model.

And of course if you create your own views, they handle both the drawing (drawRect) and the interaction.

https://developer.apple.com/documentation/appkit/nsview?lang...

>So where does the misunderstanding come from? It comes from recent changes in how developers (ab-)use GUI frameworks. I haven't full grokked how this came about, but it seems to be part (a) widget toolkits (b) horrible drawing APIs and (c) the iPhone with LayerKit/CoreAnimation. This change has been that for example, when there is just some dynamic text to draw, people have been using text-label widgets instead of just drawing the damn text in drawRect. So suddenly you have people constructing, adding and removing views at runtime as a matter of course, rather than as something done in exceptional circumstances, which I gather is what you (rightly) object to. However, this is not the "programming model" of GUI frameworks, it is an abuse of those GUI frameworks.

Not sure when your "recent" (in "recent changes") refers to.

That's how GUI frameworks have worked at least since they've provided a widget hierarchy (with labels, containers, buttons, and so on). Delphi was like that, Swing was like that, QT was like that, GTK was like that, NeXT GUI lib was like that, Cocoa was like that, the old Mac OS 8 lib up to 8 was like that, and so on. Heck, even Athena was like that.

The GUI programmers and frameworks that have been "drawing the damn text in drawRect" are in the absolute minority, not since CoreAnimation, but since forever.

In fact, you even mention "I haven't full grokked how this came about, but it seems to be part (a) widget toolkits (b) horrible drawing APIs and (c) the iPhone with LayerKit/CoreAnimation.".

The first of those things, (widget toolkits) is 30+ year old, and has been synonymous with GUI development since forever, at least in the desktop application space.

>However, this is not the "programming model" of GUI frameworks, it is an abuse of those GUI frameworks.

Yeah, not really. Not only this is prevalent and common sense understanding of "GUI framework" in the last 3+ decades, but merely having some drawRect and co (without a Widget set) wouldn't even qualify as a "programming framework" at all, people call those "a graphics library".

"drawRect" has not been the main GUI programming tool since forever, except when a developer wanted to make their own custom widgets. Whole GUI apps never once call drawRect (or its equivalent in their lib) directly.

Thanks for some good points, as I wrote before, I haven't fully grokked this yet.

However, I am not sure where you got the idea that I denied the existence or use of widget toolkits, since they are central to the whole development. However, I don't buy your claim that the existence of widgets meant that nobody ever implemented drawRect::. That's just a false dichotomy.

For example, I just googled "open source Mac app", then went to the source for the first entry, Adium (https://github.com/adium/adium/tree/master/Source) and the first 3 implementation files I looked at all had an implementation of drawRect:: Second entry is Disk Inventory X. Includes a TreeMap framework, 5 classes, in is a view with a drawRect::.

In general, my experience is that you typically use a custom view for whatever your app is centrally about. For example, a drawing app has a custom Drawing view. A word processor has a view for the text, a spreadsheet for the central table. At the very least. Around the central view you would arrange tools and other chrome built out of the widgets of the toolkit.

The widgets are, however, not really part of the MVC pattern, they are tools you use to interact with the model, they rarely reflect the model itself (except maybe for being enabled/disabled).

In terms of horrible text drawing API, I don't know about other platforms, but for NeXTstep/Cocoa that happened with the transition away from DisplayPostscript. With DPS, text drawing was trivial and malleable. With the OSX/Quartz transition, text-drawing was delegated to ATS, with some of the most arcane, inconsistent and difficult to use APIs I've had the displeasure to use. And alas these were not built on top of the much saner Quartz APIs, which were bottom-most for everything else, but instead the Quartz text APIs were trivial and very limited convenience wrappers for underlying ATS calls. Sigh.

(And I realise that this is quite a while ago. (a) Yes, I'm old (b) I don't think the text APIs becoming horrible was a trigger, they already were when things changed)

The type of app that only used the widget set definitely also existed: these were the business/database apps or the like that just interfaced with textual/numerical data/tables. Those you often could build using just the widgets as-is, without ever creating a custom view. Apple concentrated a lot on those use-cases in their public communication, because NeXT's focus had been business apps and they made for great "look ma, no code!" demos.

Of course, these widgets aren't really connected to a wider model, they contain their own little model and MVC triad. In the case of Apple, they tried to fix that with bindings[1], but that was only a partial success. So the ViewControllers (which already existed, I think) jumped in and the "update view" part of MVC became "set the content object of this widget". This can actually work fairly well, if you really treat the ViewController as a View (this is entirely permissible, MVC describes roles, not objects) and really, really only do that update when you get a notification that the model has changed. Alas, that isn't enforced or even supported much, so you get arbitrary cross-view modification. Sigh. Slightly better support would probably help here, for example Notification Protocols[2].

So that leaves addSubview, adding and removing subviews for dealing with dynamic data. I'd still maintain that this is a fairly recent development as a major way of achieving UI dynamism, and I also think that its rise roughly coincides with the rise of the iPhone. And I also think that, even though this technique is now widely used, the basic widget sets aren't really well equipped to deal with that way of working, or with helping developers not make a hash of things. Because that's not how they were designed. They were designed to deal with fairly static hierarchies of views that manifest themselves and any dynamic content on the display using drawRect::.

[1] https://blog.metaobject.com/2014/03/the-siren-call-of-kvo-an...

[2] https://blog.metaobject.com/2018/04/notification-protocols.h...

The problem with drawRect is the fact that texture upload is too slow. So instead of redrawing your text each frame and uploading the resulting bitmap to the GPU, you upload it once and then only change its shader’s uniform parameters which are cheap to vary (e.g. position, alpha, etc.). The textlabel object is nothing but a handle to this pre-rendered texture through which we can vary the shader parameters.
> The problem with drawRect is the fact that texture upload is too slow.

You have a font render shader, and that renders to the texture, what's there to upload?

Yes and no.

You are right in that changes to drawing induced by the original iPhone are responsible for at least part of the widgetization of CocoaTouch. The first iPhone(s) had a really, really slow CPU but somewhat decent GPU, so moving more rendering functions to the GPU made sense.

Originally, Cocoa as well as its NeXTstep predecessor did essentially all drawing on the CPU (some blotting on the NeXTdimension notwithstanding). And this was usually fast enough. At some point, window compositing was moved to the GPU (Quartz Compositor). With the phone, animations were both wanted for "haptics" and needed in order to cover for the slowness of the device (distract the monkey by animating things into place while we catch up... g ), and the CPU was also rather slow.

So instead of just compositing the contents of windows, CocoaTouch (via CoreAnimation) now could and would also composite the contents of views. But that's somewhat in conflict with the drawing model, and the conflict was never fully resolved.

> texture upload is too slow

First, you don't have to have separate textures for every bit of text. You can also just draw the text into a bigger view.

> redrawing your text each frame

Second, Cocoa does not redraw the entire screen each time, and does not have to redraw/reupload the texture each time (if it is using textures). It keeps track of damaged regions quite meticulously and only draws the parts that have changed, down to partial view precision (if the views co-operate). Views that intersect the damage get their drawRect:: method invoked, and that method gets a damage list so it can also optimise its drawing.

Now if you actually have a texture living in the GPU and you are incapable of drawing into that texture, then you must replace the texture wholesale and the rectangle/view based optimisations won't work. However, I know that they do work, at least to some extent, because we were able to optimise animations on an iOS app by switching from layer-based drawing to a view with drawRect:: and carefully computing and honouring the damage-rect. It went from using 100% CPU for 2-6 fps to 2% CPU at 60fps. (discussed in more detail with other examples in my book: iOS and macOS Performance Tuning: Cocoa, Cocoa Touch, Objective-C, and Swift, https://www.amazon.com/gp/product/0321842847/ref=as_li_tl?ie...)

Third, if your text does change, you have to redraw everything from scratch anyway.

Fourth, while the original phone was too slow for this and lots of other things, modern phones and computers are easily capable of doing that sort of drawing. The performance can sometimes be better using a pure texture approach and sometimes it is (much) better using a more drawing-centred approach (see above).

This misses the point completely. I would love Cocoa to work the way React does, but it doesn’t. At all. The main point of React is not having to manually manage view updates. You just write a pure fuction from app state to view (State → Html) and the runtime figures out how to update the existing views to match. That way you can completely forget that the view has some state, you just manage the app state and provide a bunch of pure functions that map various state fragments to views.
React surely has higher level widgets than Win32 (and Cocoa, and TK, and all those decades old stuff), but it is the same State -> View logic. The desktop widgets that are still getting updated, like QT, have widgets with roughly the same level of abstraction as the web frameworks.
…but it is the same State -> View logic.

It’s not. I am familiar with Cocoa. When the model updates, the controller or the view notice and manually update the view state to match – update text fields, change colors, push new views, etc. This way the correspondence between model state and view state is hardwired into imperative, mutating code:

  func updateView(model: Model) {
      if (model.updating) {
          statusLabel.text = "Updating…"
      }
  }
In React-like architectures, the view state is never mutated from the programmer’s perspective. The programmer just writes a function that takes the model state and produces the view state:

  func buildView(model: Model) -> View {
      return Label(text: model.updating ? "Updating" : "Idle")
  }
So the correspondence between the model state and the view state is declarative, pure code. That’s a huge conceptual difference, because it makes the result much more convenient, error-resistant and testable.
That's Massive View Controller pattern with widgets.

You might want to check out Model View Controller, with things like drawRect:: and "setNeedsDisplay" or "setNeedsDisplayInRect:"

Widgets and Massive View Controller are built on top of the MVC framework, and can be more convenient in cases. However, that doesn't mean the underlying MVC framework has disappeared.

UPDATE: And yes, the terminological confusion is awful.

Concept Shadowing and Capture in MVC and its Successors

https://blog.metaobject.com/2017/03/concept-shadowing-and-ca...

Model Widget Controller (MWC) aka: Apple "MVC" is not MVC

https://blog.metaobject.com/2015/04/model-widget-controller-...

Here's how it's done with qt :

    Label { 
       text: model.updating ? "Updating" : "Idle"
    }
it's not implemented on top of JS but is a proper declarative DSL for reactive programming
>React surely has higher level widgets than Win32 (and Cocoa, and TK, and all those decades old stuff),

Higher level, but much lower quality -- the feature set of GUI widgets as offered by desktop SDKs is unmatched in the HTML/DOM world. It's like actual objects vs play-doh.

React is not MVC.

I mean, for a start, no 2 MVC frameworks actually agree on how to pass data around.

React is just the V.

WPF in dotnet uses MVVM is quite can different but express some interesting dynamic behaviors.
> Is there anything out there that you guys feel is superior?

React is just one of paradigms. And UI is a multi-paradigm entity. When architecture of one component can benefit from React model, others - may not.

Consider basic <input> as a component. In order to update its value you just need to execute this:

    input.value = "New value";
Wrapping such input into React.Component is a waste of resources.

As for me Twitter's Flight ( https://flightjs.github.io/ ) is less constraining - more general if you wish.

It is just very simple infrastructure around PubSub idea. Loosely coupled components interact with each other by posting UI lifecycle events. Components subscribe themselves to such events and react on them in most optimal, component specific way.

Some of components may use React internally, some have better means to update themselves.

If you have complex state MobX is very nice and performant and works with Typescript well.

Apollo is also nice. It's best for display heavy apps as documentation and typechecking is at least enforced/built-in. But I feel it's too abstracted/magic for heavy state apps. I still need to find good flow with Typescript and Apollo though. (to not repeat types - haven't tried yet really).

Redux IMO is overkill and is/was abused. It's good if you want to store some global data/config and have clear view od it. But for very dynamic state MobX is much less overhead.

I would just like a good way to share components and simpler styling.

BTW for simplest state management I like pure class implementation and just calling update on main component after event handler finishes. It's easier to test and good enough for simple UIs.

I always felt like Polymer's component model (with "use the platform" as a motto/basis for implementation) had a bigger overlap with the kinds of problems a UI toolkit was supposed to solve though the frontend community seems to like React's approach better so far.
I'm curious what specifically you find that Polymer did to solve those problems (and what those problems are in the first place)? I've worked quite a bit with Polymer and React, and felt that there wasn't really an idea behind Polymer about the best way to solve problems - it seems to mostly be about promoting use of Web Components beyond just reusable date pickers and the likes.
First, I do dabble in frontend dev but I'm more of a backend person. I never used React and briefly played with Polymer 2.

Shadow DOM and custom tags make it possible to closely mimic the way we used to do UI development back in the Delphi/VB6 era. I like how eg. css properties only apply to a given component.

Polymer seemed like the most lightweight possible way to implement this because it uses the browser facilities. I understand that React also has components and custom tags (JSX) but it doesn't use browser facilities but rather implements them itself, which just sounds like the wrong way of approaching the problem.

Polymer only uses browser facilities at the most basic level. As soon as you get into data binding/data passing/callback/events, Polymer becomes ... weird.

Still my favorite one is "Commas in literal strings: Any comma occurring in a string literal must be escaped using a backslash (\)." here: https://polymer-library.polymer-project.org/3.0/docs/devguid...

React is Javascript through and through, and yes, it only uses browser facilities. Because JSX is not custom tags, it's function calls: https://reactjs.org/docs/react-without-jsx.html

From what I understand, Web Components and Polymer have a ton of fundamental limitations, starting with how data in a component tree is bound to the DOM as strings, so for anything even mildly complicated you have to roll your own JSON.parse / JSON.stringify handling into every component and have to deal with the DOM parsing exploding if you dump too much data into it.
"component tree is bound to the DOM as strings" You can pass data as props instead of attrs, same as with react - https://github.com/Polymer/lit-element. I wonder why this pop's up all the time.

It is true that polymer had quite a bit of limitations, but there are other solutions like stencil, lit-element, svelte or vue (yes it can output WC's) that do not have those problems.

Lit-html in latest version I think is only outperformed by inferno from popular solutions.

That's still converting attributes to/from DOM strings, which seems likely to end up in bad places once you've got a huge amount of data.
Well... Despite Polymer's repeating of "use the platform", I always felt React used the platform far more than Polymer. In the end, React is just a way to structure an application that generates and manipulates regular HTML. In other words, you can use shadow DOM and custom tags just fine. If the browser supports it, that is - and if you've used Polymer since before Web Components were standardised (HTML Imports still aren't and will never be), that was a major downside, and the opposite of light-weight.
In practice polymer was slow, because franeworks like react get their performace by batching updates, and polymer couldn't do this because the components didn't know about each other...
Well, React concepts is not new at all. Things like data fetching and state management are done in Desktop UI frameworks more than a decade ago. All the praise around react is because they did it well on the web.
The best paradigm I’ve found is the way the Common Lisp Interface Manager (CLIM) works. Unfortunately, there aren’t any implementations available that look “modern”, but you can get a feel for the api on Linux.
I also think it’s a really great idea to use a declarative approach sprinkled with imperative code for logic. Combined with the smart diffing of a component tree this is really quite powerful and also easy to grasp for most developers at the same time.
Immediate mode UI systems are p nice.