This post represents my perspective of events and could depict an imagined narrative. I'm reflecting as I believe the Hooks announcement to be the most important turning point in front-end development in the past 5 years. And that its impact is still being felt today and will continue for years to come. I'll leave you to be the judge.
On October 26th 2018, React announced a feature that would change the whole frontend ecosystem. If you somehow have not seen this talk you can find it here.
To paint the picture. React had pretty much conquered the frontend world. After 2 years where people had floated around this idea of "JavaScript Fatigue" and depicting a fractured landscape of frameworks of the month, React had come up on top. Sure there was Vue, and Angular. But most of the random libraries had faded out to obscurity. React had hit a milestone rising above a declining jQuery.
React 16 had consolidated and streamlined the rough edges. The vision could be seen as React had successfully shown it could be used for Native development as easily as the web. And there seemed to be many promising features coming in the near future. Things were looking up.
Initial Reaction
Inside React
After introducing the concepts of Time Slicing and Concurrent mode earlier in the year, I'm not sure anyone was expecting anything else new. Sure we'd just gone through a cycle from Smart/Dumb components, render props, through to things like recompose, it felt like things were settling down. Maybe it wasn't perfect, but React seemed to have the solution for any problem.
The announcement caught most of us off guard. The solution was so elegant and straightforward. We get to use our function components and have the full power of state too by breaking class lifecycles into a number of event subscription methods or "Hooks". Not only did this clean up the code by letting us group state/action/effect by feature, it cleanly solved the problem of mixins and extensibility gone since React.createClass
.
I mean the value was apparent before Dan had even finished talking. Those HOC stacks living above our component definitions were going to turn into simple almost declarative JS blocks. This was clean and really a game-changer. Somehow in one swoop, they had solved everything.
Outside React
I listened to a podcast recently where Rich Harris, creator of Svelte reflected on seeing Hooks for the first time. He thought looking at them that people wouldn't accept them and was generally surprised at the response.
Admittedly, I was equally surprised at how well the announcement went over. I could have sworn Dan Abramov had just told React developers the future of web dev was KnockoutJS/MobX. The API and composition patterns were so similar. I love KnockoutJS and had held React's philosophy ultimately what lead to its declining mindshare.
This seemed crazy and people were eating it up. I could see why. They appeared to solve every issue I had with React. Could I finally drop reactivity and learn to love React just as much?
I think the direction both made sense and confused other communities. One take was sure React was aligning more with Functional Programming. Others honestly were thinking, "Didn't we finally get classes in JavaScript, what do they think they are doing?" Quite a few libraries like Vue were following to this point trying to work out what ES Classes would look like in their frameworks and React had already changed the paradigm again.
Honeymoon Period
Inside React
In the first 3 months, there was like a renaissance. People were creating use____
collection repos and everything that could be a Hook would soon be a Hook. For the most part for all our simple examples this was amazing. Form validation, store interfaces, animation helpers, time/date helpers, the list goes on and on.
Then someone tried to make a counter. You know a simple counter you see everywhere and the number didn't update. It stayed 1 forever.
import React, { useState, useEffect } from "react";
import { render } from "react/dom";
const App = () => {
const [count, setCount] = useState(0);
useEffect(() => {
const timer = setInterval(() => setCount(count + 1), 1000);
return () => clearInterval(timer));
}, [])
return <div>{count}</div>;
};
render(() => <App />, document.getElementById("app"));
And that was the first moment we realized things were not what they had seemed all along. Well, we knew the Hook Rules so why not add stale closures to the list? And well using the function form of setCount
solves this anyway so let's just do that everywhere.
The other thought of course was, maybe we don't need Redux? Context API plus useReducer do a pretty good impression. Honestly, do we need these external state libraries anymore when React has all the tools built in? Even Redux itself in version 6 had moved to use React's new Context API by the book.
Outside React
I am pretty sure independently at within a day every author of a reactive UI library had an epiphany. "React is never going to be the best Hooks library". Something didn't quite seem to add up. The Hook rules were an indicator that there was a gap between the mental model and reality.
The Hooks API mostly was a pattern very familiar with reactive developers so they could almost immediately see this gap. One has to imagine that Rich Harris of Svelte's conflict over the syntax made him reflect on what all these libraries were missing. He landed on all we needed was adding reactivity to the language of JavaScript so all this bulk could be shed.
Evan You from Vue probably was thinking, "Hey, we already have a library that does this. The solution is simple and we can do it without all these Hook Rules". Very quickly he announces Vue will be exposing their reactive system in Vue 3.
For myself, I was still in disbelief of the React announcement as Solid's API was almost already identical to Hooks before they were announced. But they had solved my getter/setter problem with tuples. It was the last piece I needed, and I realized Solid could be a library worth persuing as not only was it performant but it was the closest API surface to React, without the oddities and people seemed to like this. I wrote my first article in Nov 2018 and haven't stopped writing since.
First Year Out
Inside of React
Hooks have replaced almost everything. Honestly, the hype was justified. There are Hooks everywhere. People refactored their projects. The new React feels pretty great.
It turned out Redux wasn't in fact dead. The Context API has performance issues if using React's state for change management and it made a quick u-turn in Redux 7 to using its own subscription system.
If anything Reactive libraries like MobX started to see a decline but hey, Michel Westrate creator of MobX released an awesome library (Immer) that makes using Redux even easier.
Other libraries started to show up too to better handle the data fetching layer and using Hooks made them seem that much easier to bring into our projects.
So yes, there are a few hiccups with hooks. We still occasionally forget dependencies but our linter finds them quick. And occasionally we have to force it to shut up when we want that empty dependency array.
To be fair we were never so good at understanding how React works until now. When we look back at our class components we realize that it was fret with perils we never even knew. Our code though should be more performant and better written than ever.
Outside React
March 2019, Svelte 3 lands and it is a big one. Rich Harris tells us that we more or less have been doing way too much for way too long and all we really need to do is get rid of it. He has successfully taken reactivity as part of the language and put it on display in a way no one can deny. Small, performant, easy to use, all the boxes are checked.
Vue announces that it is dropping its proposal for Classes and replacing it with a function API. This later becomes the Composition API a foundational piece of Vue 3 which provides "Hook-like" Reactive primitives to the framework which have none of Hook Rules or closure issues. The community is torn but Evan guides the ship masterfully.
Many other libraries added Hooks in the same manner as React. Preact had made a big change with Preact X introducing Hooks and many of the new React 16 APIs. It did cause the library to put on a few pounds but by September 2019 we had an alternative to React with the same modern API. There were also several cool projects like Augmentor that add hooks to any renderer/web component.
As for Solid I already had the primitives I wanted. Instead I spent that year implementing every React feature I could find so that I could bring it to feature parity in the browser. The last of which was experimental Suspense and Concurrent support that landed in fall 2019.
Two Years Later
The first year of Hooks saw reactive libraries rise to the challenge of creating the best primitive-based frameworks. React had inadvertently opened the door to a place where reactive libraries long considered their strength. React still flourished in their own right, but this was a big place for libraries to gain mindshare.
The second year, saw something even more incredible for React. Homegrown global state libraries succeeded using React's own primitives like Recoil, Hookstate, etc... They could tap into React's own primitives in a more optimal way than ever before. But something unsettling still is lying below the surface.
Other libraries like Svelte had grown and Vue 3 was released. These libraries spent the 2nd year working on developer experience and it shows.
But the one thing that has become most apparent is when asking the question "How to best do X in React?" the answer has become a lot more muddled. In the past, it was a discussion over which abstraction was in style. This has been replaced with discussions over how React internals work. And the confidence in answers is greatly reduced even before some smart alec chimes in "But that could completely change under Concurrent Mode".
This feeling is probably best captured in Jared Palmer's React is Becoming a Black Box
So What Happened?
For the longest time, it might be easy to attribute the wait for Suspense and early experimentation around Concurrent Mode as the clear catalyst for the state of things. But I attribute this all back to the Hooks announcement.
Hooks are both the best and worst thing to ever happen to React. I empathize because I've been there. You spend years reflecting on what could be made better, and realize that if you move all your pieces in a certain way you can cover all the gaps. It is even congruent with your vision as you've lived through it. However, people outside of you never saw what you saw in the first place, and now that they do they aren't sure they like what they see.
React was never going to be the best Hooks library. You don't need to be the best at something to do well. But what if you are subjectively the worst Hooks library?
React Hooks are genius. Perhaps too genius for the average developer if they need to understand what is going on. React kept all the benefits of their VDOM, view = fn(state)
powerhouse of a renderer, with all the flexibility of granular declarative data approaches, at the small cost the developer needing to be aware of when things update.
Reactive systems aren't any simpler really, but they have this write and forget aspect to their granular primitives. Svelte or Vue have this perceived simplicity from this even though mechanically in some ways things are more similar than you'd think. React's approach is arguably even purer than Vue in that it ties into the very nature of the VDOM instead of trying to duct tape a reactive system on top of it, but no Vue developer is thinking about it.
In addition, React's greatest appeal to many was its unopinionated approach to shared state management. React having introduced its own primitives naturally displaces those other libraries. It doesn't force them out, but API surface overlap and the knowledge using React internals is more beneficial doesn't help. Especially true of invasive reactive libraries like MobX.
Where Do We Go from Here?
Now the React team hasn't been working on nothing the last couple of years. And I'm confident that all will be revealed soon enough. And React is still will continue to be the most used frontend library. But something has forever changed.
Some prominent React developers have jumped ship. It will be interesting to see if their new journeys will scale out as well. React was born out of a desire to simplify the render model after several years of, you guessed it, event-driven/reactive libraries. We should be cautious to throw away all we've learned. These things tend to swing like a pendulum over-correcting initially.
Others have turned to reduce state management as much as possible in React components. This included other forms of state management to drive React from the outside to avoid any need for whatever the React team was cooking. XState a state machine library in particular has grown in popularity among a few others.
For better or for worse we need to acknowledge front-end libraries are more similar now than they have ever been, and that creates a completely different dynamic on the competition. This lends to being more cutthroat about things like performance and size all things being equal.
We're seeing things now like JSX-Lite which compiles a common JSX API to the framework of your choice. And I wonder will Metaframeworks of the future in a desire to keep their options open be built to support multiple frameworks? This is difficult precedence to set with the desire for new unique features. But maybe the risk-averse are ok with the lowest common denominator.
Maybe this would have happened eventually anyway. But React opened a door that day that can never be closed.
Top comments (20)
It is nice that you took some time to take a step back and think about (some of) the changes the front-end world has gone through. It seems like we still haven't solved the question of what is the best way to write web applications. Which is a normal thing because best will have many definitions according to who asks the question. I see the same battles going on in the Haskell community as to what is the best way to structure Haskell applications.
Hooks are definitely extremely useful to Facebook, and the advantages in terms of packaging reusable functionalities are clear by now. The initial communication was more around the fact that classes are bad (?) or writing less code (?) and the likes. But one key value is reusability. The other is composability. These are desirable stuff. They help write programs faster (no better program than the one you did not have to write) and maybe in a more reliable way (reusing pieces that have already been tested).
We already know some of the downsides (you mentioned a few): stale closures, hook rules, etc. One that is not often discussed is that hooks introduce a much stronger coupling with the React runtime than ever before. That is what is behind the name, you are hooking in React internals, so you need to understand those internals. Hooks are far from being a functional abstraction as you need to know the internal details of their implementation (that becomes even more apparent when you try to test one hook in isolation), While people somehow think that React is following functional programming paradigm, it is the exact opposite that is true. It is getting away from the functional paradigm and going deeper into framework land. Functional components, as they are called, are rarely pure functions. Functional programming is not programming with functions. Then, all effects have to be controlled by the React framework. And again that framework gives you some surprises (cf. dev.to/poeticgeek/in-react-compone...) which I expect to increase with concurrent mode.
None of this really matters. People will always be able to write web applications with React if they put in enough effort, and there will be a whole industry teaching them those efforts. The same is true with Vue, Angular, Ember, vanilla-JS + web components, etc. I don't know how the 'competition' will involve but I think it is more of a promotional story and capturing developer mindshare rather than actual differences for the end user.
The issue that we have in front-end programming is precisely that because we use frameworks that are incompatible between each other, we end up in a situation where we duplicate a lot of work. You have a
subdivide
library for React (cf. github.com/philholden), then you duplicate that for Svelte, and for every other framework. We would write that in vanilla JS (or a web component) and everybody would be able to enjoy it rather than rewrite it.This sounds like obvious but this creates incentives for coalescing around a single framework to avoid duplicating work, or simply maximizing the reuse potential. That is a winner takes it all situation that favor the creation of monopoles, with its set of advantages and drawbacks. That is more what worries me going forward. Next.js is amazing but it only works with React. There are some reasons to this, but not so many. You could have a Next.js that is framework agnostic, there is just is no incentive to it. The same is true for a few other things (running applications on the edge, and more).
I do remember the moment when Facebook decided to change React licensing (for very valid reasons if you ask me). That served as a reminder that you do not want to have a dependency that is too strong over something that you do not control. As I said before, the React tie-in is only getting stronger.
This is fine. React is fine. So is Vue. But I hope we can achieve a vision of interoperability based on standards, that reflect the interest of several actors and the community rather than primarily that of Facebook. There is a lot to gain if we can achieve true reusability. Web components is a step in that direction. I wish that the corresponding standards would grow in use cases that they support and in adoption at least in the enterprise. Then folks can pick whichever framework they want, freely. Or they could choose none. It is interesting to have a look of how web components have improved in the last two years too.
I hope we will be able to have layout, server-side or edge-side rendering libraries that are framework agnostic. I see how WebAssembly is changing the game in the cloud and at the edge by being language-agnostic. There is a lot to gain there.
As a side-note, folks interested in actual functional programming applied to client-side web applications can have a look to that series of articles (as the author of Solid, the last one may be of interest to you):
In short: no context, no hooks, no weird stuff, mostly functions, mostly pure functions.
I think one lesson from OO history is that reusability while attractive is an elusive goal. Seems component replaceability is more important for systems longevity - so composability is where it's at.
Initially React's concept of a component was very much object-based where the render function's "associated functions" (handlers) were attached to the same object as the render function (function components at that time didn't need additional support or access to React managed state).
However HOCs were kind of an unwieldy way of composing non-presentational capabilities.
With hooks a component's "baggage" was moved from an object to a closure opening up compositional options more fine-grained than the components themselves.
Elm at its core relies on a VDOM as an adapter to the mutable DOM. I suspect that a Rust inspired imperative programming model of "reasonable mutability" may be more appropriate for browser-based applications.
It may even turn out that SPA's are an evolutionary dead end. They made sense back in 2013 when the web was still predominantly accessed through equipment with large core single thread performance connected via relative reliable networks. These days personal computing has shifted to handheld devices where low-power/spec small core CPUs are becoming more common and while on paper cellular networks can be quite capable, real world situations can quickly turn network quality to meh.
By using a ServiceWorker as a device local web server proxy MPAs can be quite responsive (Beyond SPAs).
Also I think that people need to manage their expectations regarding the impact that WebAssembly will have on browser-app development (not talking about cloud/edge here):
From that perspective I think that common expectations that WebAssembly will "normalize" browser app development towards what people are used to from desktop or native are misplaced. If anything a I think a leaner approach that maximizes the use of the browser's natively implemented capabilities (i.e. more than it's JavaScript engine) is indicated (e.g. Svelte seems more like an extension to the browser rather than React which seems intent on "replacing" it in it's own image).
My point about WebAssembly is that by targeting a common standard agreed on by many vendors, developers have the freedom to develop in several languages (Rust, C, C++, Go, and a few more in a growing list). That allows to reuse and compose existing software written in different languages. In short, we have reusability, we have interoperability, and we have composability (well the specifications still have to improve in that direction with interface types and module linking to make this friendly but we'll get there eventually). That is a benefit of standards that are agreed and negotiated on by several vendors. I am opposing that to the closed world of frameworks.
Before WebAssembly we had Google NaCL as an attempt to run native code written in other languages. That was proprietary and not really interoperable. WebAssembly is opening a world of software in the browser, in embedded devices, at the cloud, the edge, you name it. That is why I say that there is lot to win to achieve interoperability instead of duplicating libraries or solutions for each framework.
So that is an example of the benefits of standards. Standard can succeed when they are enough low-level and well-designed that you can construct higher abstractions on top of them.
Even Go is exhibiting the problems that I was highlighting. A simple "Hello World" file generates a 1.3 MB
wasm
file. One way to whittle that down is to use TinyGo - but this comes at the cost of features and acceptance of limitations.Many consider C#/Blazor another hopeful but that also clocks in at a 1.6 MB
wasm
for "Hello World" due to the overhead of the .NET CLR.Compare that to a suggested JS performance budget of 170KB (0.7MB uncompressed) for an entire page (where the runtime already exists in the browser).
And people who think that the Networks will save us will be disappointed. Consider this quote:
Networks are experiencing a similar phenomenon. Subscriber growth and demand is outstripping the gradual theoretical improvements in peak performance and capability, often resulting in a degradation of the average network quality experience in some areas.
The majority of existing software hasn't been written with the constraints of the web in mind - be it issues like the "subset of the Go" supported by TinyGo or that web content has to work without the luxury of prior installation or the constraints imposed on generalized distributed computing by the "laws of physics" or security.
As a result there'll be a lot of rewriting where people are expecting reuse. WASI will improve things but at this point it is unclear how far browsers can actually go, beyond existing Web APIs, in exposing "operating-system-like features" to remote content.
Sure. But the reality is that the browser is the client runtime for the web, not the operating system the browser is running on (and in the mobile space the OS fragmentation is getting worse, not better).
Yes but in embedded systems, the cloud, and the edge we are talking about installed software, not just-in-time delivery over a perhaps questionable network which web content has to contend with - installation of PWAs is optional (usually to support offline functionality), not mandatory.
The issue is that for decades we have enjoyed the benefits of Moore's law to create the additional headroom needed to afford new abstractions - but that's done now.
As developers we are entering a phase where we need to make harder choices of where we are going to spend our users' runtime resources. This has been historically an issue for the video games industry which typically had to work on low(er) cost platforms. So they have been using Data-Oriented Design (Shooting Yourself in The Foot With OOP) and Entity Component Systems - and other industries are starting to notice.
So it seems only natural if the web at some point will divert away from the monolithic (SPA-style) apps that are preferred on desktop and native.
Related:
Why the #wasmsummit Website isn't written in Wasm
Polyglot WebAssembly
Yeah I think I understate this. I do mention that by providing their own primitives they now have an opinion, and basically push some of the 3rd parties out. But you are saying it's more that by encouraging proprietary primitives it ensures lock in. All that being said I always felt React = FP thing was fictional, marketing hype thing. React = React simple as that.
I think your FP stuff is in the same category as XState where some people are actively searching ways to pull all state management out of React for this reason.
That being said I don't feel this is some sinister or even Facebook driven motive. Reactive libraries like Vue or Svelte have the same proprietary buy in on their primitives. Sure you can export the reactive system and use it elsewhere, but every detail in how it interacts with the templating and components is very much specific. These systems are just as invasive and promote lock in.
I think React was attempting to provide a composition model they could do smart things with. When you consider things like Suspense/Concurrent Mode and like these isomorphic stories. The only way we can do things smartly is to know what we are dealing with. When we are we done rendering etc.. Have the means to be able to orchestrate at a higher level that was part of their offering. You can do it other ways but they saw the need to ship with it for the next feature set. I think that was the motivation with the timing of this.
And that's the problem with the standards. Framework authors still feel like they are moving this stuff forward at such a pace standards aren't really catching up. Even if the client side render is becoming well understood, SSR and isomorphic is opening up completely new doors. Even Svelte in the client with their approach to animations is suggesting that standardization is a ways off.
So while I'm saying I think we will see this work to be agnostic. It will be the lowest common denominator of libraries. You will see the frameworks themselves accelerating in directions that aren't generically followed.
Personally I was on this train of standardization about 5 years ago. But as I worked more on my frameworks and realized the overhead cost, It is achievable but never quite as good. I wrote libraries to generalize reactive rendering (DOM Expressions is still bring your reactive system), swore by webcomponents, and thought that I'd land on TC-39 observable spec as basis for reactivity. In the past 5 years I realized everyone of those was a trap, or mostly useless beyond simple demos. It was something one can do but would never be the "best" way. Not today, never. Maybe new specs and new approaches changes that but fundamentally these do not align with the direction of things as they unfolded.
Of course there is enough of a desire for this that it will be a thing. And there will continue to be this tension. And it will be completely doable. However, there will be those (mostly from frameworks) that know their specialized solution is more optimal.
Generosity/portability/maintainability always comes with some overhead and performance loss. In traditional non-frontend development we always talk about breaking down into smaller, purer, more testable functions, using more interfaces that help doing better abstractoin, avoiding lock between business logic and particular frameworks. All these come with runtime overhead, or, at least, more compiling time for, say, rust.
It's always a tradeoff. ;(
Is Svelte not compatible with the Observable API? The library Effector is too. What precludes it from being the best way do you think?
I mean sure you can always make an adaptor. And it looks like Svelte supports Observables right out of the box since their stores are subscribables. Most other reactive libraries can take a subscribable and have it write to one of their own primitives in a similar way.
So to clarify I don't see any problem if you prefer these different global state managed solutions. And I'd welcome people bringing other reactive libraries for global state management if it made sense as the interopt layer is fairly painless.
I was just saying that using Observables for the frameworks internals is less optimal than lighter weight subscription mechanisms. It can be done and I went down that path at one point, but it was bulky when it came to my templating goals. Mostly that spec Observables are cold, an unicast in nature, and we often want our reactivity hot, and multicast at the framework level. You almost always want Behavior Subjects using the RxJS term and mapping between them constantly is a bit tedious. I've seen some work to reduce this overhead though. RxJS-Autorun is a great little library geared at bridging that gap. I already played around with making a version of my renderer to use it, and it wasn't bad.
You can even use composable primitives to bring them into the library closer and replace local state management. But in those cases using the libraries own primitives is going to be the most performant. You remove any translation overhead. In most cases this is going to be minimal, so I wouldn't sweat it if it's your preferred experience. But like Svelte or React team is only going to be optimizing for their localized cases. Even Svelte stores adds a little bit of extra on top of Svelte's component reactivity. Again nothing worth worrying about, but there are tradeoffs. Mostly that the frameworks will continue to build more features that might demand more interaction points that will make these things potentially bulkier. It's really a decision of how much you value the cleanliness of your logic and how much you want to leverage framework unique traits. I'm not going to say anyway is right for all cases.
Yeah I see where you're coming from, you're always going to have to build some sort of layer on top of observables and whether that meshes with your design goals depends. Thanks for getting back to me!
I still find hooks to be inherently unfriendly to the human mind. Classes are friendly and were the fruit of many years of programming evolution/wisdom, which hooks basically throws in the trash, all because of hatred of inheritance. Inheritance is only one feature of classes. They also serve as natural mental/organizational models. With hooks, figuring out what is going on based on reading code is much harder. If the goal is functional programming and code sharing, I've never understood why that could not be more simply accomplished within the class paradigm by using functions instead of methods and passing them what's necessary, even "this." func.apply(this, ...) isn't that hooks in a nutshell?
With respect to state management, it seems quite clear that we need both global and local state. It would be nice if both were handled in the same way so that they could be used interchangeably depending on scenario. I view that as the biggest problem. Mobx solves it quite nicely. And by tracking change automatically at all nodes of a state tree, offers optimization that would be hard to exceed in any other fashion.
I mean that is a bit of what of Vue 3 has with their Composition API. The reactivity is independent somewhat from the Component lifecycle.
You might like my library Solid. It's basically if you created a library purely from MobX (I needed to make some changes for performance reasons). No VDOM just reactivity. A simplistic view is everything is a series of nested
autorun
s. State management local and global is homogenous. It's all just a matter of scope.That being said I like the function component part of React. So when I make the comparison to MobX it's based on the reactive data and not all the decorator/decorating stuff that people associate.
This is the first I've heard of
JSX-Lite
. It's a very cool idea, but I don't think it really "compiled to Svelte" how I would have hoped...Thanks for taking a look and great catch - try this to see how to accomplish what you are going for
JSX Lite has some basic rules that must be followed that we are working on docs and an eslint plugin to catch and guide to the right practices we properly support
Yeah, this makes sense. To be fair, I didn't read the docs so it makes sense now that what I was trying didn't work. I may still try this out for one of my Svelte projects.
To be fair I believe it is still in alpha. I think there are a lot of rough pieces right now, but it is interesting they've conceptually have a means to pull off this sort of thing by identifying the similarities in state management. There are a number of edge cases I believe in terms of execution timing, so we will see as it develops, but the idea seems promising.
Yeah, for sure. It's a very cool idea. I really hope it pans out. I moved my personal projects off of React and onto Svelte, I really miss JSX vs their template syntax.
Where I stand these days is Svelte is great, but I don't want to give up the good parts from React.
My personal slant is what lead SolidJS to use explicit syntax with JSX while doing the compilation/reactive no-VDOM thing. Turns out it is really performant being explicit while harnessing the flexibility of JSX.
Great article! Love the questions raised and good to know I'm not the only one questioning where do we go from here
Class components where horrible, thank god we have Hooks now! It is amazing how clean my components are with hooks.