25 ms·
React == Windows 3.1
by Papirola 8y ago
React == Windows 3.1
- acemarke 8y agoThis 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/ https://www.bitquabit.com/post/the-more-things-change/ Prior discussion: https://news.ycombinator.com/item?id=10381015 https://news.ycombinator.com/item?id=10381015
- mpweiher 8y agoOr 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-functions-of-model.html 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.
- Marazan 8y agoReact 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.
- danabramov 8y agoHmm 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.
- mpweiher 8y ago> `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-functions-of-model.html 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 https://en.wikipedia.org/wiki/Graphical_Kernel_System [2] https://en.wikipedia.org/wiki/PHIGS https://en.wikipedia.org/wiki/PHIGS
- zoul 8y agoThis 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.
- marcosdumay 8y agoReact 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.
- zoul 8y ago…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.
- mpweiher 8y agoThat'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-capture-in-mvc.html 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-mwc-aka-apple.html https://blog.metaobject.com/2015/04/model-widget-controller-...