top | item 19067302

React as a UI Runtime

343 points| danabramov | 7 years ago |overreacted.io | reply

151 comments

order
[+] sktrdie|7 years ago|reply
I think React is a big deal because we can finally think of UIs as pure functions of data.

However, the entire mentality of the community is moving towards having behavior tied to specific portions of the tree; in essence it's common-practice to have stateful components. With Hooks this is even more the case.

Instead, the nature of UIs is that changing something in a part of a UI might and will effect something in a completely different location: when I click the button, open a dialog, show a spinner and reset the user profile screen.

The problem with writing stateful components is that the behavior (such as the one above) is tied to the UI representation (at which level of the tree should I write this logic so that it effects all the aforementioned components?).

We are essentially going back to tying logic and representation; something that we've been trying to avoid over the past decade or so.

I'm not saying React doesn't allow you to do differently; things like global-state (Redux, MobX, etc.) allow you to separate behavior and representation quite well. I'm more confused about the recent lack of best-practices surrounding this idea of separating logic-and-UI, and instead they're pushing towards: "Yeah now with Hooks you can even more easily bundle logic-and-UI together and have them tightly coupled". Which to me seems really confusing.

[+] adamkl|7 years ago|reply
I’ve become a big fan of using finite state machines (more specifically xstate [1]) to encapsulate all the logic and states of a particular UI. You can essentially create all the behaviour of your application without writing a single line of UI code. At that point, you can use React exactly as you described, as pure functions of data.

[1] https://github.com/davidkpiano/xstate

[+] baddox|7 years ago|reply
I don’t think this criticism of hooks is valid. A hook that exposes a “incrementCounter” function could be implemented with local component state, or global state via React context. The developer could trivially swap in one implementation for another.
[+] resters|7 years ago|reply
The issue is that the component abstraction makes thinking of state as being specific to a subtree feel better encapsulated then having all components enmeshed with global state in their own way.

Doing it in a way that best utilizes the strengths of both of those abstractions will happen eventually, but old habits die hard. As evidence look at all the convoluted ways people try to make all style information public, conflating the public aspects and implementation details.

There is just a ton of sloppy thinking and very little design pattern leadership. For example Airbnb used react for a long time and all it really gave back to the community was an extremely anal set of linting rules which incidentally differ from Facebook’s in annoying, nit picky ways.

One can imagine the amount of bike shedding that such minutiae creates across the entire react community.

[+] oftenwrong|7 years ago|reply
>I think React is a big deal because we can finally think of UIs as pure functions of data.

A bit like a decade ago and earlier when we still used server-side rendering:

request parameters + backend state = some html

[+] drbojingle|7 years ago|reply
Hooks can be abused but they have their uses because some state is temporal. Forms before they're submitted and animations are two good examples. There's no need to store local animation state in a global state store every time you use a new component.
[+] littlestymaar|7 years ago|reply
You essentially have a tradeoff between two kinds of coupling:

- either you're coupling the logic and the representation.

- or you have coupling between your different UI components and the global application.

You're talking about the first kind of coupling and say it's bad, but IMHO the second kind is even worse in some cases.

There is no silver bullet, it's all about tradeoffs.

[+] dustingetz|7 years ago|reply
React gives you pure functions of tree-shaped state. Nesting and recursion got a lot easier with React and we built more complicated stuff.

But I think we are learning learned that complex state is graph shaped. There aren't any good answers here. You need a real graph "database" in the UI

[+] namuol|7 years ago|reply
I think we're confusing coupling with co-locating. Hooks actually make it easier to separate things like side effects and state management from a component when compared to the status quo of class based components with lifecycle methods.
[+] lewisl9029|7 years ago|reply
I'm a huge functional programming fanboy myself (my first full time job out of college was a Clojure/ClojureScript gig, by deliberate choice), so a completely pure mapping from state to UI sounded like a great idea when I first started diving into the world of UI programming.

Soon however, I realized that in practice (at least in the context of a React-based application), there's little to be gained by storing state that is truly temporal/localized in a persistent/global store (which is necessary for enabling a truly pure mapping of state to UI), and that there's in fact much to lose, because:

1) By nature of being temporal, they're state that needs to be initialized when they need to be used and destroyed afterwards, otherwise we risk exposing stale state to the next usage in time.

The initialization/destruction process often needs to be synchronized with some lifecycle of a component. Animations on mount/unmount, and form input that needs to reset when closing a modal, etc, are great examples of this.

If we used component local state to begin with, that state lives and dies with the appropriate component automatically, with no additional ceremony.

On the other hand, if we were to store that temporal state in a persistent state store, we'd still end up having to create components that hook into component lifecycles to create/destroy that state at the appropriate time in the persistent store manually, which, even if we ignore that it's often a tedious, error prone process, means introducing impure components into our tree of pure components anyways, so we've really gained nothing over the component local state approach.

Not to mention that temporal state is often frequently updated (as an example of an extreme, FLIP animations (https://css-tricks.com/animating-layouts-with-the-flip-techn...) by nature require at least 60 state updates per second), and having a few of these in a persistent state store can wreak absolute havoc on application performance if we mess up even a little bit in our pure rendering optimizations, which is notoriously tricky to get right perfectly due to all the edge cases we have to be mindful of (not creating new event handlers functions with every render is especially tricky in a codebase that's committed to using only "pure" components; in fact, I'm not sure if that's even possible in the strictest definition, since all the techniques I've worked with involve creating an impure class component to memoize the function, and the new useCallback hook likely isn't pure in the strictest sense either).

2) By nature of being localized, they're state that no other component should ever be concerned with.

Making them accessible at all to other components, as we do by storing it in a global state store, is by definition a leak of implementation detail, which over the long term makes it harder to change the components that use localized state, because we have no easy way to guarantee its "localized" state isn't being depended on by something else. In fact, to suggest that they're using "localized" state at all at this point is more wishful thinking than anything else, because nothing exists to enforce this localization once we put it in the global store.

At best they're just extra noise we need to ignore/filter out when debugging/serializing the state of the store, and at their worst they can lead to extremely brittle and over-entangled component trees where changing one part of the tree can inexplicably break seemingly unrelated parts.

On the other hand, component local state is for all intents and purposes, truly localized. We cannot access component local state outside of the component itself unless we explicitly expose it to children as props or to parents by refactoring it up a few levels, at which point we're making the explicit decision to change the locality of that state to include more/different components, and that decision is completely self-evident.

Whenever we decide to use component local state, we can rest assured knowing that their locality is enforced by the React runtime, rather than some handwavy global store access convention that we'd otherwise have to resort to if we stored localized state in a global store, which involves an ongoing cost in terms of enforcement while offering little in the way of real safety.

To be perfectly honest, some/all of the points I mentioned could potentially be attributed to React not abstracting us far enough away from the stateful nature of the underlying platforms it builds upon (the DOM for web, native UI platforms for React Native). For the case of temporal state, I can imagine for instance a potential alternative/higher-level library where React's stateful lifecycle hooks are replaced with some elegant purely functional primitive for supporting the same use cases, perhaps something that models _time_ explicitly as part of state, like Datomic does with transactions (nothing similar comes to mind for handling localized state though, so perhaps encapsulation and true purity are just at odds on a fundamental level).

Though I have not yet seen anything that would enable a truly pure state -> UI mapping for building non-trivial applications while avoiding the aforementioned drawbacks, I'd of course happily re-evaluate my position on the feasibility of this approach when I encounter such a solution.

[+] m0meni|7 years ago|reply
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.
[+] rpedela|7 years ago|reply
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.

[+] preommr|7 years ago|reply
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.

[+] cageface|7 years ago|reply
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.
[+] scarlac|7 years ago|reply
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.

[+] jdc|7 years ago|reply
From my dabbling with QT's QML, I gather it would be a lot more concise than React for some use cases.
[+] mhd|7 years ago|reply
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.

[+] panic|7 years ago|reply
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.
[+] jcelerier|7 years ago|reply
Qt's QML is React with 1/3rd the bloat in terms of code
[+] Papirola|7 years ago|reply
React == Windows 3.1
[+] platz|7 years ago|reply
WPF in dotnet uses MVVM is quite can different but express some interesting dynamic behaviors.
[+] c-smile|7 years ago|reply
> 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.

[+] m_fayer|7 years ago|reply
This article hit a rare perfect note for me, I wish there was more documentation like this out there. Instead, the choice is often between very basic introductory stuff, API docs, and step by step "how to build a todo list" tutorials. What all those things miss is the theoretical motivation and the primitives that have been established to address that motivation. That's where I'm happiest starting when I try to pick up something new, since I feel that all the details snap neatly into place once you understand the ground level stuff, but to get this ground-level view I have to hunt for independent articles, online courses, or books, when it should exist in the official docs.
[+] debt|7 years ago|reply
This is a fundamental problem with most programming languages I’ve come across. It’s quite annoying.
[+] self_awareness|7 years ago|reply
Flutter uses React model for creating UI and it feels very nice. I would be happy to use this model for standard desktop UI programming as well (Qt, Gtk+).
[+] longnguyen|7 years ago|reply
I'm working on react-qml[1] to pursuit that exact goal: bringing React model to desktop UI development. Thought you might be interested. We're running this in production for over a year now and quite happy with that. Team's productivity improved a lot, mostly because of better tooling for desktop development:

  - Write codes in ES6/7 or TypeScript (transpiling using babel).
  So the syntax is exactly like what you're writing on the web (not React-like syntax)
  - Bundling using webpack (with a sensible default, zero-configuration FTW)
  - Use any front-end library (redux, lodash, rxjs, redux-observable etc.)
  - Supports Hot Module Reloading (sub-second reloading)
  - Supports react-devtools & redux-devtools (Time Travel Debugging possible)
  - Super easy to test & debug in multiple platforms

The problem we're facing now is that it required both React & QML knowledge. In the new version, I'm working on completely new APIs to support developing desktop application using only React. Would love to hear your opinions on this approach.

[1]: https://github.com/longseespace/react-qml/tree/next/packages...

[+] vnorilo|7 years ago|reply
I have experienced two times a leap in productivity that subjectively felt like a game changer. The first was from a baseline of a good MVC kit like Cocoa or pre-QML Qt to the MVVM paradigm, and the second was to React (with ClojureScript and Reagent).
[+] revskill|7 years ago|reply
What's a UI Runtime ? The post should give that definition first before jumping into the details.
[+] Vinnl|7 years ago|reply
You might want to follow the link behind the first mention of the word "runtime": https://en.wikipedia.org/wiki/Runtime_system

So in a nutshell: "React as a UI runtime" considers React as implementing part of your UI's execution model. In other words: instead of your code having to call appendChild, setAttribute, etc. to modify the UI, React does that.

[+] danabramov|7 years ago|reply
It links to the “programming runtime” definition on Wikipedia the first time that term is used.
[+] szines|7 years ago|reply
Other framework, like Ember, uses so called Run Loop to solve these problems. Quite similar concept, but it is not only for UI, it is for the whole app (route, state management, interactions, etc...) Maybe it could be interesting if someone would like to dig deeper in this topic.

https://guides.emberjs.com/release/applications/run-loop/

[+] platform|7 years ago|reply
I like it. Here is my own rendition of Dan's approach (interleaved with experience from about 12 K lines of React native/ react native web)

A ) Dependency Tree (eg dom or virtual dom) is the interface user interacts with.

B ) Each interactable element in the tree can have its own state.

C ) Each interactable element gets data or update data from/to its own state.

It can also get data from 'properties' that a parent passed on (but the interactable cannot update those properties itself, instead it must call its parent's function to do that)

D ) After the above A, B, C are setup -- the code interacts with the state, not with UI elements

E) The UI runtime is a collection of mechanism that supports A, B, C.

This includes :

1) Primitives allowing Interactable to be attached and interact with the dependency tree, ability to receive data from parents

2) Well defined (from both APIs, callbacks, and Data) primitives -- that enable state management within the Interactable, and across their dependency tree

This also includes mechanism deciding efficiently, which state changes affect which Interactable)

3) Developer friendly run time helpers to debug and manage the above

----

Cleary A) --> can be a dependency tree of Excel cells, or Matrices, or robot's extremities, for that matter.

Clearly B) (the state) is widely appreciated these day ViewModel (as it is called in Android's new JetPack LiveData components)

The state is also the thing that can be validated, even with TLA+ (which is what am thinking about, in a downtime).

And it is much much easier, in my view to map interaction business rules to state, rather than to UI.

---

I am looking forward to try this with my console UIs project.

---

I also have a strange feeling, that this model will work when I have to manage complex backend interdependencies,

where updates to distributed caches affect the algorithms running across a server farm.

---

[+] Zooper|7 years ago|reply
For people that feel the virtual-dom is anything but a hack, please read up on this: https://github.com/Polymer/lit-html. Do you really not get a code smell from keeping an in-memory copy of the DOM and doing "Reconciliation"? Most of this article is about the vdom.
[+] BossingAround|7 years ago|reply
> This is a deep dive — THIS IS NOT a beginner-friendly post. In this post, I’m describing most of the React programming model from first principles. I don’t explain how to use it — just how it works.

Ok, now that author feels better, let's move on..? Or what is the purpose of such 'disclaimers' and 'warnings'? Let the reader see whether the article is at their appropriate level, don't patronize...

I really dislike these. I can skim the text, and within 30s, I can see whether it might be my level or not. This feels, however, that the author is purposely driving me away for no other reason than 'you don't make a living with react, so shoo, this is for the big boys'.

[+] breatheoften|7 years ago|reply
The author is well-known and well-cited -- especially for introductory articles about using react and react ecosystem libraries. I think he wants to make it clear to anyone that happens upon or is recommended the article that the contents of the article are not 'required knowledge' for using the library.

I think this is reasonable for this author to want to emphasize. It's quite common for a beginner to make one of several reasoning mistakes that might push them away from trying something or push them away from something they were already using. The beginner who hasn't used a thing yet might think 'I need to understand how this thing works in detail before I can use it' in which case they might think reading an article like this is an appropriate way to get started. The beginner who has already started using a thing might think 'here is a good article about how the thing I've been using works in detail which I can't understand -- therefore this thing I've been using must be too hard for me to use and I should look for something else'.

I assume for popularity retention reasons, the author doesn't want to encourage either of these kinds of mistakes.

[+] WA|7 years ago|reply
The author of the article is a contributor to React and the author of Redux. So the disclaimer is valid, because lots of people read his stuff and might expect some React tutorial or whatever.
[+] nindalf|7 years ago|reply
I know nothing about React. I opened this article, saw the disclaimer and closed the tab. It’s quite possible that if I hadn’t read the disclaimer I might have tried to read it, decided React is waaaay to complicated for me to learn and never tried it in the future. I think Dan wants to avoid precisely that scenario - scaring away noobs like me from ever trying React.

Of course, he didn’t consider the massive inconvenience he was causing to god level programmers like you when writing his disclaimer. Shame on him!!!

[+] cprecioso|7 years ago|reply
In addition to what the sibling comments are saying, the author has explicitly stated in past posts that he doesn't want this knowledge becoming job interview questions, as (in his opinion) these are non-leaky abstractions that don't affect one's productivity/code-quality on React.
[+] coldtea|7 years ago|reply
>Ok, now that author feels better, let's move on..? Or what is the purpose of such 'disclaimers' and 'warnings'?

To tell people what to expect going in, so they don't have to lose their time if they're just starting out and looking for a quick high level tutorial etc.

[+] mlevental|7 years ago|reply
when did it become popular to criticize the form of a technical document? what is the value of /your/ post?
[+] erik14th|7 years ago|reply
React sure sounds interesting, what puts me off of it is its license.

edit: disregard that...

[+] kaoD|7 years ago|reply
What's wrong with MIT?
[+] aliswe|7 years ago|reply
This really isn't a fanboyish idea, I hope, but doesn't anyone else think that Windows should support some kind of javascript UI natively? One can just feel that they aren't improving their own dialogs etc as fast as they would like because of implementation complexity...
[+] coldtea|7 years ago|reply
Yes, we absolutely need an order of magnitude slowdown and more memory use on our desktops.

Why should Electron users have all the fun?

[+] blitmap|7 years ago|reply
I had hoped we were moving toward that with Universal Windows Platform apps. :3