The point of an abstraction is to create a "black box" of sorts around some primitive. I think all it boils down to with what the author is saying is that the React team is changing how things work under the abstraction, and therefore some assumptions people made about leaked semantics are no longer true.
Mithril rendering semantics have always been more or less this: on an event, redraw everything. React semantics started that way too, but now there are a whole lot of other semantics under the hood (for example, the rule of hooks provides some semantic guarantees that enable a hot reload implementation to be more robust). Concurrent mode is another example of semantics that benefit from rule of hooks guarantees.
I think when I see people complain about the rule of hooks is that there's a dissonance between the strict semantics of hooks and the expectations of what the semantics should be (for some definition of "should", usually related to ability to reason about stuff in some specific way)
I'd say that overlapping several different compatible underlying functional semantics under one umbrella of very strict API semantics is an interesting and somewhat novel approach to supporting some cool infrastructure (i.e. ability to do deep hot reloading stuff, animate in IoT devices in a renderer-agnostic way, React Native, granular reactivity via memo, and the list goes on). Where I think React missed the ball a bit is that the API semantics don't always feel ergonomic for the use case they're meant to serve (for example, I've seen a few occasions where nested hooks ended up w/ long code review threads debating obscure minutiae)
When I see people praise Svelte, I think the reason is similar: since it doesn't need to artificially create constraints to support every use case under the sun, its API semantics are able to align very closely to people's expectations.
Well said. Perhaps my deeper point is that hooks and soon Concurrent Mode force devs to come to terms with the fact that they _don't_ understand React internals (hence my usage of black box) and that their mental models were wrong this whole time (although some might argue still pretty productive).
I also think Crank is SUPER interesting on so many levels. I built a few demos with it and am fairly impressed. However, practically speaking (and I'm putting my developer relations hat on), I think its generator API is just too intimidating to junior developers.
For those that do, this isn't an issue, and for those that don't, this isn't an issue either. Their mental model may be flawed, but as long as the IO is the same, do they really care?
Concurrent mode isn't really a black box. Its just a shortcut to throw away work that would otherwise be invalidated.
Is Concurrent Mode basically a way of addressing performance problems in React, or is this in some way a feature that adds something novel? Or is it just a side effect of an unwillingness to move away from functional programming?
I write React at work, but write Svelte or Vue at home, and I've always found React's abstractions to be the most hard to reason about, and from the looks of it CM will make this more challenging (??). Thanks.
That said it's still a mental shift. Sometimes I feel like I'm writing React and not writing JavaScript.
https://github.com/dai-shi/will-this-react-global-state-work...
with concurrent mode i think of what could be, web applications that can compete against native for the first time. as well as making making components that are resilient to async issues / making async a high level concept. there's a little churn for sure (for library devs, and a specific subset), but imo completely worth it.
Native apps feel better than web apps because they have robust UI libraries that web apps do not. React concurrent mode will have zero effect on that.
If the argument is "React concurrent mode will make web apps faster so that they feel more native", my response would be to use something like Svelte, which is available today and is considerably faster than React. React is slow.
Concurrent mode may make React faster but it'll just be making up for React's past mistakes, not the web's.
With what React is attempting currently your app will render as much as it possibly can while maintaining stable 60fps, the rest gets deferred while it can differ between lesser and higher-priority updates. If you doubt how important scheduling is, look at practically any feasible list component, they're all virtualized. With React every aspect and corner of the application is like that. In theory it could outperform native apps.
Btw, there are countless of robust desktop apps being made with HTML: VSC, Whatsapp, Skype, Spotify, Notion, Hyper, Discord, Slack, ... thought most of them will still feel sluggish compared to a native counterpart. React will change that.
VSC: chokes on files larger than several mb Slack: eats all of your memory, often hangs and just whites-out while I figure out what to do. Skype: has this app ever actually been good? Spotify: not sure I'd call it robust, but it's functional...enough.
> In theory it could outperform native apps....thought most of them will still feel sluggish compared to a native counterpart. React will change that.
My understanding is that native apps hook into far lower-level functionality and run with _signficantly_ less overhead. They simply execute faster, and far more directly. I don't see how React and needing to go through react-framework -> JS -> V8 -> etc would possibly compete with that, let alone outstrip them.
The problem is essentially the same. Native apps are also conflicted with load, they have better means than we have on the web to deal with it, but it's still low-level and complex to orchestrate, threading for instance. Any one of those means pushes your app into async issuee, race conditions that you need to reconcile. With concurrent mode scheduling is a first class concept, your components won't be subject to race conditions. React maintains 60fps, high-priority content (user input, animations, transitions) can be ran fluidly while lesser priority content gets deferred. It has a good chance of outperforming multithreaded native apps with that model.
This demo illustrates the issue: https://youtu.be/nLF0n9SACd4?t=172 which is universal. You run into this on native platforms as well as on the web.
Isn't the likely way forward to move the computationally heavy parts of the app over to web workers and to keep the main thread almost exclusively for UI work?
What's your definition of component?
Mithril was sufficiently thin for me to drop into the debugger, say "oh, that's how it works" and fix.
I'll take a look at crank though. I do frontend dev only to make my hobby projects accessible to friends and family, so the less to remember, the better.
Isn't that exactly the point that the big image on the front page is making? If most people have a mental model of a technology that doesn't match what the company is putting out, it makes very little sense to blame the people who have the 'incorrect' mental model. If it wasn't so widespread, your point would be much stronger. But the fact that the core pieces of react are misunderstood, especially when React publishes documents explaining how all of this is supposed to work and how you're supposed to think about this is an indication that something is wrong with React, not the people who use it.
While you're right that we shouldn't "blame the people", I think blaming the company / library in this case doesn't fly either, given the specifics.
The "incorrect mental model" people have about React is based on two things:
1. the prevalence of OO concepts in programming education and in practice in most engineering teams
2. the introduction of class abstractions onto JS prototypes by the ES spec.
followed by:
3. React bundling things like `createReactClass` and encouraging class abstractions in their docs in the pre-hooks days
While the 3rd point above may have been a mistake on the part of the React team, I do think points 1 & 2 are much bigger factors here.
> something is wrong with React
The only thing "wrong" with modern React is that they're challenging the status quo in popular programming concepts with something they believe is a conceptual improvement.
You can disagree with them on whether it represents a true improvement, but saying they're "wrong" because their conceptual model is a departure from the status quo is pretty reductive.
What makes this point tricky is that React did initially introduce their library with OO concepts for years.
To put that in context: that was at the time ES was starting to introduce OO abstractions to the spec. and it was somewhat trendy to go in that direction. I never got the impression that the React guys were heavily invested in that paradigm, and they definitely moved away from it very quickly after first encouraging it in their API. Everyone makes mistakes.
As a side-note: I think class abstractions in ES are a feature that in retrospect is less of a great idea now than it may have seemed at the time. ES class abstractions obscure their own subtle issues (in a very similar way to the article's fake Twitter screenshot jokes about React hooks).
- From 2008-2014, _everyone_ was writing their own "class-like" abstractions (see: Backbone, Class.js, five million other "inheritance" libs). So, the React team wrote `createClass` as their own implementation.
- When ES6 classes came out, the React team took that as an opportunity to drop maintaining their own abstraction and switch to something that was actually standardized, and reduce the amount of magic behavior (auto-binding, mixins, etc).
- Function components came out in React 0.14, and were initially limited to just rendering based on props - no state or effects possible
- Hooks now give function components the ability to have state and effects. In addition, encouraging a move away from classes dovetails into the React team's long-term plans for the React APIs.
The class abstractions added to ES spec. didn't happen in a vacuum; it was very much on the back of community demand. Backbone especially had an outsized influence.
Perhaps that was a necessary step toward realising tools to solve problems without those abstractions, I don't know.
Whatever the case, just because we wish solutions to those problems were easier to understand doesn't mean reality owes us that. I suspect React in particular, being in the web dev space, has a lot of people working with it who have very little CS background. Because they don't understand how React works under the hood or even above the hood is "something wrong with React"? I'm not sure I buy it.
I've seen a lot of really poor React code that breaks all kinds of best practices, many of them explicitly laid out in the docs. Even before hooks came along. In fact it's been hard to find examples of people who understand the dom well, much less React. I will continue to suspect there's something wrong with most of the people using React, not React itself, which from my perspective has only become better over time.
> has a lot of people working with it who have very little CS background
This and so much this. This applies to "frontend development" in general. I work as a contractor in the frontend space (Europe, no where near FAANG like companies) and very often I meet other "devs" that have basically become frontend "engineers" out of being a webdesigner - like you know, creating nice html templates for wordpress, having decent CSS and photoshop skills and later in their career started to copy-paste some jquery plugins into their template to get nice animated toggles and alike. It is very common in "frontend teams" that people started to get into JS out of webdesign, and have never actually programmed in any other language.Another issue is even with people with a CS or another STEM background, they only get taught in the "traditional" OOP sphere on top of blocking thread environments. Those usually have a hard time wrapping their heads around higher order functions or async-based development (and to be fair, I also had a hard time when I first encountered it).
I don't disagree, but my follow-up question with that statement is "ok, now what?"
If you've got a weak/inexperienced developer who's stuck in a framework where they have have to start grokking async/HOF/whatever to solve the problem they've encountered, where do they go from there? It's fine and good to blame the framework they're operating in to be shitty, but they a) didn't have the skills initially to make a solid decision about the framework to use, and b) are now likely stuck with it (unless they're going to do a rewrite with something else).
Early cars were hard to learn, drive, and maintain. Over time they got better via trial and error by manufacturers. The desktop IDE's of the early 90's were like this, but got better over time (until web ruined their market). However, the web is still stuck in 1903: simple things are esoteric. Perhaps because too many other things about "cars" keep changing? Something is wrong. CRUD web dev is a mess.
To my mind they are oftentimes magic pixie dust that can turn a hideous, verbose and inflexible API into something humane and readable.
If you bring up a scenario, I can probably poke holes in it. Done it many times in many debates. I don't mean to sound arrogant, but I keep winning THIS one for whatever reason.
I literally can't write more than 100 lines of clojure without accidentally shadowing a function binding with a variable binding. I think the only way to break the habit would be to abstain from common lisp for 6 months or longer.
(mapcar my-func my-list)
and it throws void-variable and then I remember that I have to add the #' reader macro to have it read as a function not a variable. (mapcar #'my-func my-list)
It just takes some time to switch the mental model over each time. Clojure did get me in the habit of using unique names for all functions and values because accidentally shadowing a function binding is that more difficult mistake to debug.In practice I haven't missed the flexibility of a lisp-2, if anything it's just made my code more readable because my names are forced to be more descriptive
Can you elaborate on this? On first glance it seems the same, just with a syntax that uses different symbols than HTML?
Lit-html, which is using template literals, is another good option.
[0] - https://staltz.com/some-problems-with-react-redux.html
It's probably because I've been reading and writing HTML for +20 years though.
hyperscript is about as close to a middle ground as we can get. It's compatible with JSX for the folks that really really want to see angled brackets, while still being uniform javascript like other API variations (div(), html`<div></div>`, etc). The lit-html syntax is not bad either, but template strings did not have as widespread support back when mithril originally came out.
Since the framework isn't interested in chasing trends and since it provides extension points via lifecycle methods, there's really nothing novel that needs to come from the framework itself.
I know some of the more popular frameworks make it seem that webdev is constantly in churn/evolving, but if you look at React for example, other than the hooks paradigm shift etc, it hasn't really changed all that much in scope over the years either (the same can be said about other libraries as well).
For example, Mithril could easily be used w/ coffeescript when that was still a thing, and people use it with typescript these days too without much fuss since TS is also a project that decouples well. And this is with zero changes to the framework. You can integrate dragula or plupload or google maps or whatever via lifecycle methods as you always could too.
So, TL;DR: I think the focus still remains on making it as stable and robust as possible
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/87f2...
That comes with some very real downsides - mostly getting jsx to work requires a bunch of extra (ugly) tooling. On the other hand, very complex components look very clean.
Hyperscript when you have a relatively nested dom element gets quite messy and hard to visually parse for me.
- jQuery - Backbone - Ember - React - ???
Skills I learned in college about writing SQL are still relevant today, several decades later. Skills I learned coding for iOS (even Swift!) years ago are still relevant today. CSS and HTML skills I learned decades ago are still relevant, etc etc. Python/ Django knowledge from 10 years ago is still largely relevant. React/ jQuery/ EmberJS/ Vue/ Angular/ Grunt/ Gulp/ Webpack/ Underscore/ CoffeeScript/ etc... damned near every Javascript library I've ever worked on has an extremely limited lifespan in terms of relevance. Even within React, it's hard to keep relevant. Class based React? We're doing Hooks now!
> why is that a bad thing?
It's only bad if you have to try and maintain 10 year old Javascript and in order to do it, you have to learn a whole new paradigm. IMO it's doubly bad right now since so many people are abandoning semantic HTML and more or less rolling everything as their own custom components.
My post was in response to a suggestion that the fix for all the React issues was in fact replacing React entirely.
Just start with creating web components in Svelte, include them in existing React code, and slowly phase out slow, and old tech that React is. This is just frontend lib, why are people so religious about this. You still use Node, JS/TS, etc.
Im I troll? Don't know, but that is just what I did year ago. Now I just laugh when I see articles like this, buy I also feel sad for small entrepreneurs that have to pay big $ for code in "dated tech" - thinking "they are on the edge".
It's promising, especially for smaller projects/MVPs, but I still have no idea how well it will scale with app size/team size (and have yet to see good evidence that it does it well).
I just find it ironic that people dog on React for being the "default", but then also can't recommend Svelte fast enough, seemingly because its just "not React".
In our setup with parcel we didn't get good error messages and line numbers (it spit up internal compiler errors), but it might have to do with our setup. Trying it at home with snowpack it gave comprehensible error messages.
"This system is hard to work with" -> {Abstraction created} -> {Abstracted extended to support new features} -> GOTO 10
Now you have n+1 systems to learn & reason through.
For a long, long time, I thought that to provide the values that React brings, the UI framework being a black box is inevitable. Almost all React-esque libraries including but not limited to React, Preact, Mithril felt like a very thick abstraction over the DOM APIs.
But then I saw Crank.js[0], and that felt very intuitive and a thin abstraction, while retaining the good parts of React-esque libraries. I don't really know why it feels like that - I'm guessing it's because it uses native JS features that you already have a good understanding instead of some magic that happens in the React runtime.
I'm very looking forward to it, and I would like to urge everyone to try out Crank.js if you feel that React is now not intuitive enough.
[0] https://crank.js.org