Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
What's New in React 18? (yagmurcetintas.com)
146 points by nathias on Sept 29, 2021 | hide | past | favorite | 153 comments


Not sure where I stand on this. On one hand function components and hooks give a nice way to extract logic into small reusable bits, way more than with class components.

But on the other hand it becomes clear that decent performance with this approach requires all kinds of tricks and each react version adds more and more of these tricks with a steep learning curve. Shame since react started out with a very small, easy to understand API and that is what made it so popular.


You know, i'm not even sure that hooks were worth all of the problems with maintainability and readability that they've caused.

I don't have the slightest doubts about me being in the minority here, but i've seen a large amount of projects which attempt to use multiple state hooks per component, and as a consequence the dependency arrays become brittle as the code is changed and sooner or later you're stuck with your page being in an endless rendering loop, because your logic isn't clever enough to actually untangle all of the state to decide when it needs to change anything:

  useEffect(() => {
   ... // a whole bunch of code
  }, [foo, bar]);
  
  useEffect(() => {
   ... // a whole bunch of code
  }, [bar, baz]);
  
  useEffect(() => {
   ... // a whole bunch of code
  }, [foo, bar, baz]);
Sure, you can be responsible with that stuff when you're the one writing the code, but when you open up someone else's project and have "the business" breathing down on your neck but have to untangle their uncommented code, you feel like some of the features are footguns in disguise. At least with shouldComponentUpdate all of the code that decides whether something should be done was in one place.

You could easily comment that code out or change it. But with hooks, you need to untangle how all of the related calls to setState work and where every method for every state hook is called and why. I'm not sure that it was a good idea to decouple those.


I’m with you.

They’re confusing. The magic is too high. They maintain state in an invisible way. The abstractions are hard to follow, especially when you roll your own.

The key issue for me is that they hide the rendering lifecycle from you. Everything’s implied. One of the complaints with classes was that you had to learn the arcane weirdness of the lifecycle. But a) it’s not that weird and b) it’s much easier to learn when the callbacks are named after the stage in the lifecycle. The hooks way makes all that invisible.

That said, I’m quite fond of the ‘[value, setter]’ return type from useState. It’s nice to use and nice to write. Just don’t ask me to explain how it works for multiple re renders.


Yeah, and sometimes it feels like I'm writing a really cumbersome dialect of javascript.

I mean, something simple like:

  let i = 0;
  const inc = () => i+=1;
becomes:

  const [i, setI] = useState(0);
  const inc = useCallback(() => setI(currentI => currentI + 1));
Every single thing needs layers of abstractions upon layers of abstractions.

For all the hate angularJS got, at least with dirty checking your javascript was just plain javascript. I'm leaning more and more towards svelte, which offers this, but more performant than with dirty checking.


> const inc = useCallback(() => setI(currentI => currentI + 1));

This might actually even have a bug and would need to be even longer to properly function :-D

I think you need to add [i] as a dependency, no?


No. I'm using a callback in the setter which gives me the latest i and the setter never changes. If instead I would use setI(i+1) I'd have to add i as a dependency, but since state updates happen asynchronous, this would have a bug when calling it multiple times before the state is flushed.


The useCallback is redundant, the rest is still valid but I'd rather have it this way than magical variables where a reassignment makes the framework do work. This way I can just find all references of "setI"


I find hooks are best when used sparingly. I once worked on a project that went all in on hooks and some bugs were very hard to track down. Stale closures can be a headache too. I've been meaning to capture the gotchas I've seen into a website. Maybe I will one day. All in all, hooks get the job done but I'm not really a fan.


It's tricky. I've had some nasty stale closure bugs too. The ESLint hook plugin fixes these, but I wish that plugin wasn't required. And some of the hook rules are puzzling at first.

But, I've had way more annoying problems using class-based syntax. Twice the code, four times the pain. And TS type inference doesn't work as nicely with classes.

Vue got it right in many ways. At least back in the 2.0 days, the last I've worked with it.


For a good while I thought I was the only one who is against hooks. It's good to see there are two of us. By the looks of the other comments here, maybe even three.


There are a number of people that dislike hooks, many of who are vocal in React threads. Basically the entire classes-are-fine camp do, and there are a few of us in the "the React team doesn't appear to understand the functional paradigm" camp.

I fully expect that in a few years React will be widely seen as a J2EE-like poster child of over-engineering shark jumping for the functional paradigm. I already do.


Hooks never grew on me.

I pretty much stopped paying attention to new versions after React 14.

KISS - keep it stupid simple.

I suspect that some Devs new to JS didn't like the various definitions of "this", and Hooks was supposed to help them out.


> I suspect that some Devs new to JS didn't like the various definitions of "this", and Hooks was supposed to help them out.

No, stale closures caused by hooks are more confusing than what "this" has ever been, especially since this-related problems are mitigated with fat arrows and class property assignment. No, as far as I understand, the driving force behind the hooks was the vision of the coming concurrent mode, for which class components posed some difficult problems somehow.


Hooks are a response to a very specific need. They do wonders in terms of what you are able to accomplish by allowing you to encapsulate side-effects and state management. If you are writing complex or large applications, the ROI is clear.

Now, there are obviously bad ways to use (no pun intended) any tool. Doing things right requires some planning, and learning some patterns. Many effects that also potentially relate to each other should be encapsulated into custom hooks, for example. And it's often a mistake to just make everything hook-dependant—think about how would a non-react bit of the page interact with this feature, or how can you unit-test without dealing with state and component lifecycles.

Learning how to do this in a way that is approachable, maintainable and that closely follows the domain model is not necessarily easy, but that is true for almost every aspect of software engineering, including how to organize functions or classes.

The same is true for things like Suspense. Again, if you have worked on a large application, you'll see that managing side-effects, data that comes (partially or fully) from a backend, and providing a clean and performant experience (no cascading, reasonable errors) is hard. Suspense answers to a real need. Whether you like the solution they propose or not, that there's throwing of Promises involved is, honestly, an implementation detail—and I'd say it works great.

And if these features are not for you, don't use them. And if React is not for you, don't use it. If you have to work on a codebase that is not well architected, full of tangled useEffects, you'd probably have a similarly bad experience if the application was class-component-based or built using a different framework.


People can write bad code in any framework. If it's that difficult to uncoil declarative state in your head the component is poorly written, hooks or not.


You can still use class components where you feel the need.


I’ve found a lot of the elegance of hooks disappears when you start maintaining the dependency lists. It’s far to easy to introduce subtle bugs or huge performance regressions with innocent looking changes.

Feels like we need a new language with lazy evaluation and a smart compiler that handles this for you for this paradigm to really shine.


What are you talking about? How did using classes instead of functions improve performance?


Certain performance improvements and mitigations for common performance problems in something like React require bi-directional interaction of state and state-related events with instances of components. Classes/objects are a pretty natural fit for that, obviously. To do the same with functions, you have to... re-create parts of a class or object system, which is what they did with Hooks.

That would be the "all kinds of tricks" the OP referred to. Not that going from one to the other is inherently a win, but that to match the capabilities and ergonomics that classes & objects come with out of the box for addressing state-related performance improvements & state-related features, with "functional" React, you have to resort to "all kinds of tricks", i.e. write your own version of some of the OO things you need to get the job done semi-cleanly (which is exactly what the React team did with Hooks).

The result, to put it in only slightly unfair terms, is that React has enabled their community to use a really bad and half-baked OO system with bizarre syntax & behavior, all so that no-one has to use the "class" keyword sometimes. They didn't do that for funzies, but because some of the things they wanted to do, including things related to performance, required OO-like features to be workable, but for whatever reason they didn't want to rely on built-in language features for that, nor tell their community that sometimes they would have to use those built-in language features. Instead they opted for... Hooks.


In general a function component does a lot more work than a class render function. Some of it is just about handling cases that we probably should have done with classes as well, but often didn't. The result is that everything must be carefully memoized (or not, it's sometimes hard to predict). For example, should you memoize a redux selector function like useSelector(state => state.x)? Should you wrap every function in useCallback? With classes we had arrow methods that ran once, while useCallback will be run every time the function component is run. We have to continuously check that function references are stable, if it matters, and if we care enough to bloat the function with various memo calls.

Now I'm not at all saying that class components are better. Hooks are mostly easier to work with. But there's no doubt that function components has me using too much brain power and lines of code on memoization. I like the new features the react team are working on, but I hope they'll eventually do something about the stable function reference problem as well.


Anyone else feel like suspense was a major step in the wrong direction for React? I've noticed so many more cases of applications breaking in difficult-to-track-down ways because of how errors are propagated with suspense. Maybe I just don't "get it".


React started as a nice rendering library. Then it was infected with all sorts of Functional Programming paradigms grafted on top of Javascript. At the same time people wanted React to be a framework for client side rendering, not the thin layer it was.

Stateless components are a good idea, but their implementation as functions and hooks leaves any JS programmer not familiar with React scratching their head. Throwing Promises for Suspense is basically Algebraic Effects. Redux and a million other libraries tried to solve data management, none of them doing it in a classical K/V store. Now every app I touch I have to find its special version of reducers and selectors.

I like front end programming and Javascript overall. Components are a nice abstraction, and life cycle hooks make sense in real life contexts. But React reeks of developers who think they are too smart for their day job and want to redefine UI programming just to render a button with an event handler.


Very well said. I've been using React since it came out, and have been pushing back on Hooks since they came out.

Class components are dead simple. A class, a setState method, this.props, this.state, and some lifecycle methods. SO easy for anyone to understand.

Function components with hooks are not. A whole new (and unnecessary) paradigm; some mysterious hooks engine that needed new ESLint rules to be created just so people can keep the weird, delicate balance in place; hooks having their own timing problems, requiring usage of useRef which the React team tries to get people to avoid; etc.

Frontend codebases used to have several layers, with React just being one of the thin ones. Now, nearly the entire frontend codebase is inside React world. I'm not a fan of this direction.


> Then it was infected with all sorts of Functional Programming paradigms grafted on top of Javascript

The whole thing has been functional programming from the start, if you know what algebraic effects are then the functional underpinning should be obvious to you as well as anyone with the slightest brush with FP. Hell, the original React prototype was in Standard ML, later ported to OCaml and then JavaScript.

> Throwing Promises for Suspense is basically Algebraic Effects

The fact that you disregard Suspense as a head-scratching algebraic effect, instead of using simple "Promises" goes to show how much the JavaScript ecosystem seems to be about fooling people into doing functional programming without triggering their gut reaction of "FP is spooky unproven thing, but Node enterprise ready!".

Imagine for a second that a Promise's .then is called .bind, put it in a thunk if you want to be extra precise and tell me what it is. Hint: It starts with "M" and it's just a monoid in the category of endofunctors.


> The whole thing has been functional programming from the start, if you know what algebraic effects are then the functional underpinning should be obvious to you as well as anyone with the slightest brush with FP.

That's a lot of hot air. There is nothing functional about React. Algebraic effects represent impure behavior in a functional programming language, such as input and output, exceptions, nondeterminism etc. all treated in a generic way. Impure behavior, including algebraic effects, is best avoided in functional programming.

Sorry to post the link again, but please read this: https://mckoder.medium.com/why-react-is-not-functional-b1ed1...


> Functional programs are constructed using only pure functions

If that's your definition, functional programs basically don't exist in the real world. Wikipedia (and I) don't agree with that [1], it specifically separates out pure FP [2].

[1] https://en.wikipedia.org/wiki/Functional_programming [2] https://en.wikipedia.org/wiki/Purely_functional_programming


You didn't read the article. How to deal with impurity is described in the article.


So what would you call this style of programming? Saying there is nothing functional about it seems like hyperbole. It's just not as pure as you'd like. I say as someone in the world of people who need to get things done, why do we/I care?

I read the article FWIW, it didn't particularly convince me. I think even writing things in the style of functional programming, if that's what we want to call it, still makes it easier to reason about the code. Confining side effects to hooks also means there's only one place we have to reason about having non pure consequences.


Functional Programming is about purity. At the core of FP is pure functions. If you don't care about purity don't use FP. There is a lot to like about React, and Hooks and so on. Just don't call it FP though.


No, it's not. The "purity" part was mostly pushed by Haskell enthusiasts, because Haskell cares a lot about purity. On the other hand, ML and its descendants don't care that much. Here's an example in OCaml:

    let add (x: int) (y: int) : int =
        print_string (Format.sprintf "x: %d, y: %d" x y);
        x + y
This is a function. It's not pure. There is nothing that's stopping me from using it exactly the same way as a pure add implementation. OCaml is still a functional programming language. As said on Wikipedia: "Functional programming is sometimes treated as synonymous with purely functional programming, a subset of functional programming which treats all functions as deterministic mathematical functions, or pure functions.". Functional programming is not only purely functional programming.


Disagree. Functional programmers often speak of implementing programs with a pure core and a thin layer on the outside that handles effects. (Read the article I pointed to earlier.)

If you don't have a pure core then you are not using FP.


> Functional programmers often speak of implementing programs with a pure core and a thin layer on the outside that handles effects.

No, they don't really. Haskell programmers tend to program like that because monads are annoying to use everywhere in your application. But this is really just the hexagonal pattern in different clothes. DDD programmers care a lot about business logic, so the core is business logic. People that like pure functional programming care a lot about pure functions, so the core is pure functions. Some people even mix both (a good example of that is Doman Modeling Made Functional, the talk or the book). I guess people that care a lot about performance would put performance at the center, at the cost of purity and/or abstraction. Basically this whole pattern is a way to ask yourself "What are my values? What's my priority when I develop software?", and to make sure that it's at the litteral center of your application.

So again, you are mixing functional programming, "functional programmers" (which I don't think means anything), and people that value pure functional programming a lot.

Which brings us back to react. Is React functional? What does it means, to be functional? I can at least try see what people mean when they say "React is functional". There are probably multiple things: 1) React is more functional than its predecessors. 2) React share values with functional programming. These are a bit fuzzy, but we can try to answer them.

1) React is more functional than its predecessors: It's surely more functional than traditional vanilla JS, jQuery and Angular. I know that before React Backbone was popular, but I don't know anything about it, so maybe Backbone is even more functional than React, which would undermine this point. I may also have forgot some important development along the way (Ember ? Meteor? CoffeeScript? I wasn't into programming at that time so it's hard to judge the popularity/influence of everything). From what I know, I'd say it's a yes. At least in the most popular frameworks (Angular, React, Vue), React is the most functional.

2) React share values with functional programming. On the frontpage of React, we can see "Declarative: React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes. Declarative views make your code more predictable and easier to debug.". That sounds a lot like what you can hear for some functional programming advocates. "Make the code declarative, be more productive, and the compiler will take care of the performance", in a way. Then there is "Component-Based: Build encapsulated components that manage their own state, then compose them to make complex UIs. Since component logic is written in JavaScript instead of templates, you can easily pass rich data through your app and keep state out of the DOM.". Making a complex UI by composing simple parts again sounds like composing functions in functional programming. "Encapsulated components that manage their own state" feels more like OO though. I can also add that the React community uses Redux a lot, which was inspired by Elm, which itself is clearly functional programming. I've heard that hooks are a way to get closer to functional programming, but I can't confirm this, as I haven't used them. As a conclusion, I'd say that yes, React share values with functional programming, though it doesn't strive for purity (in both senses of the word).

So, again, is React functional? Yes, I'd say it is. What does it mean to be functional? I think a good example here would be OCaml. OCaml is a functional programming language. OCaml also allows you to do imperative programming, or object-oriented programming. However, in the wild, most of the OCaml code you find is functional. How functional? That depends. For some people it will mean functions and data structures. For some it will be this with modules. For others, that will be monads. So in general, maybe a bit less functional than Haskell, but more functional than Python or Java. That's the same with React. When we say "React is functional", we mean "probably a bit less functional than Elm, but more functional than Angular and Vue".

You're using "functional" in a very specific way, which is usually covered by "pure" or "purely functional", which is unproductive to these kind of conversations.


I think you have to start by answering this question:

What is the benefit of being functional?

If there is no benefit then this whole discussion is moot. If there is a benefit to FP that isn't easily achievable using other styles, then does React achieve that benefit by doing FP style?

Or is React leaning on the cachet of FP for marketing purposes?


> What is the benefit of being functional?

For React, the idea is building the UI as a function of the state. The benefit is to make the code easier to understand, debug, test, etc. I don't think I have to discuss with your the benefits of pure functions.

> If there is a benefit to FP that isn't easily achievable using other styles, then does React achieve that benefit by doing FP style?

I think it does, partially. Though it isn't going as far as something like Elm.

> Or is React leaning on the cachet of FP for marketing purposes?

I would almost say the opposite, React succeeded at first because it didn't push too much the functional stuff. Elm went farther, and doesn't have the market share of React, because insisting too much on FP, especially at that time, would only scare away developers. If you start to go the FP path, at some point you realize that using JavaScript can't work, and you have to switch to something new. People have experience and huge codebases, so they don't want to switch. You can see the same with TypeScript. TypeScript succeeded because it embraced JavaScript, especially its flaws. That means that as standalone language, TypeScript isn't as good as it could be. But as an incremental improvement in the JavaScript ecosystem, it's good, very good.

To see what happens when you use FP for marketing purpose, you can take a look at ReScript, the current reincarnation of ReasonML.


> To see what happens when you use FP for marketing purpose, you can take a look at ReScript, the current reincarnation of ReasonML.

Reason has always felt weird and half-baked. It had all that nice syntactic sugar for the benefit of javascript developers — but in the middle of it, there was some OCaml ugliness, like different math operators for integers and floats, or special treatment of recursive functions. Plus a half-baked async story, or lack of unicode support. It was all very weird.

But in other areas: I understand Swift was a great marketing success, and it is heavily influenced by FP, right (I haven't used it personally, so don't know). And so was Kotlin?


I agree, I like OCaml, I like JS, I'm not a fan of Reason. It just feels off somehow, and half-baked.

From my limited exprience in Swift, it does have functional parts, although I don't know if that's the main focus of the language, or just a nice thing to have.

Kotlin seems a bit more functional than Java, although Java has been catching up recently (sealed classes, pattern matching, record).


> > What is the benefit of being functional?

> For React, the idea is building the UI as a function of the state

Well, if you have state you're already not functional.

Look, React does not have to be functional to be useful! Let's not misappropriate the FP label and apply it to a tech that is clearly not functional, misleading a whole generation of developers.

React is great, hooks are OK, but FP it is not!!


> Well, if you have state you're already not functional.

That's just wrong. State will exist, wether you like it or not, and you'll have to deal with it.

Again, you're using FP to say pure FP. Is Standard ML not functional according to you?


> State will exist, whether you like it or not, and you'll have to deal with it.

Yes, state will exist... in a thin outer layer. Pure core with a thin impure outer layer. If state is distributed throughout the entire program then it is not FP.


> If you don't care about purity don't use FP.

This is unhelpful. I don’t know if I’ve ever encountered this attitude before, I’m enthusiastic about FP and I frequently direct people toward FP principles wherever I possibly can. Dissuading application of those principles in part because they’re not applied in (your view of) full is sending people in the wrong direction.

And you might not care, but I do: it’s also gatekeeping. Making people feel like what they’ve learned to make their code more functional, less side-effecting, and generally easier to reason about… making them feel like that’s not important progress they can value unless they share your knowledge and understanding of Category Theory or whatever is going to drive people away from what you want. And it’s going to drive marginalized people away most, probably from programming in general. That stinks.

The level of purity you’re demanding isn’t even claimed by most functional languages. And the ones which do use Monads as a sleight of hand to make the claim, but that’s plainly a useful fiction.


> > If you don't care about purity don't use FP.

> This is unhelpful.

You have to care about purity. The benefits of FP hinges on this. Saying you don't care about purity is the same as saying you don't care about FP.

That doesn't mean that anything less than "perfect purity" is worthless. You have to always aim for purity, even if you don't always achieve it, because without it there is no FP.


> That doesn't mean that anything less than "perfect purity" is worthless.

This is more helpful. I’m not going to add my own unhelpful reaction to the rest of what you said, I think I already added more value above than I’m inclined to now.


> There is nothing functional about React.

The whole concept of React is to model the UI as a function of the state. React was first made in Standard ML (you don't really get more functional than this). Jordan Walke, the creator, went on to work on ReasonML, an hybrid between the OCaml and JavaScript ecosystems, to try to leverage the functional parts of OCaml.

> Impure behavior, including algebraic effects, is best avoided in functional programming.

This is wrong though. Functional programming doesn't shy away from impurity. Algebraic effects are a way to handle impurity, which is unavoidable.


> Functional programming doesn't shy away from impurity.

Disagree. Functional programmers often speak of implementing programs with a pure core and a thin layer on the outside that handles effects. If you don't have a pure core then you are not using FP.


Sorry, but you're missing the forest for the trees. This is what wikipedia has to say: "Functional programming is sometimes treated as synonymous with purely functional programming, a subset of functional programming"[0]

In FP as an umbrella, purity is not a hard requirement for the entire paradigm, only a predominantly pipeline oriented style based around expressions is (in contrast to, say, C, where one generally passes a pointer to the same state around to procedures that pick and choose what to modify in that state bag, as a series of statements). Common Lisp and OCaml are often cited as examples of functional languages that don't attempt to enforce purity guarantees even in terms of idiomatic usage, let alone at a compiler-enforced level.

Using higher order functions for, say, promises (remember, they're stateful!) doesn't mean you're not using functional programming, just like using Array.prototype.map doesn't mean you're not using OOP (it implements fluent interfaces, if you haven't noticed). It's the absence of functional tools/techniques that qualifies a program as not functional.

IMHO, the unfortunate situation is that most JS people don't understand there are different degrees of functional-ness and certain guarantees only exist within specific subsets (and React doesn't conform to that subset).

[0] https://en.wikipedia.org/wiki/Functional_programming.


Functional Programming has to serve a purpose. What is the point of functional programming?

There are 3 benefits, mainly: (1) Ease of verification, (2) Parallelism and (3) Data-centric computation. (See article I linked for details.)

Of these, Parallelism doesn't work in JavaScript. Since JavaScript doesn't support lazy evaluation, data-centric computation doesn't work that well either. That leaves us with the first benefit alone. But ease of verification is reliant on pure functions. If functions aren't pure then it is just regular code that isn't necessarily easy or hard to verify.

React uses FP for a 4th benefit you won't find in any textbooks on FP: Marketing.


This article[0]? Sorry, but that's not an authoritative source, it's literally just some random guy talking on the internet :)

No offense, but your argument is kinda self-defeating if you are trying to claim that two out of the three purported benefits aren't even applicable (and I'd argue that even that first so called benefit doesn't have a great story in JS either).

Saying that verifiability is somehow intrinsically related to purity is IMHO making an overly broad generalization. You're starting from the premise that unit testing a pure function is easy, but that doesn't really generalize in any direction. Array.prototype.splice is not pure and yet it's trivially easy to test. Reasoning about the crashing potential of JS tail recursion is not easy even with purity guarantees. Large functional point-free compositions in JS have impenetrable stack traces. Valgrind et al exist so clearly it's possible to reason extensively about messy stateful things.

Different paradigms aren't oil-and-water and they don't have a monopoly on any given benefit, it's perfectly possible to mix and match features of various paradigms to achieve expressiveness, idiomaticness, predictability, etc.

[0] https://mckoder.medium.com/why-react-is-not-functional-b1ed1...


I don't see any credentials mentioned in your profile, which means we're all random guys on the internet :)

With reference to the article, it builds on top of authoritative articles (see References section at the bottom), so you don't have to take anything at face value!

You're right, I am indeed saying that verifiability is intrinsically related to purity. The concept of pure functions is at the core of FP. You take that core away and you no longer have the right to call your code FP.

Why is it important to label something as FP in any case? React is useful even if it is not functional. What I am opposed to is misappropriating the "FP" label for marketing purposes, by the React team.


> The concept of pure functions is at the core of FP.

Only in the subset that you consider canon, not generically for all FP. Wikipedia is quite authoritative, FWIW.

I agree that the React team has made some flat out wrong claims (e.g. incorrectly calling hooks pure at one point), but you're engaging in exactly the same sort of "marketing" you dislike, by biasedly claiming your specific flavor of FP is the "real deal", when in reality there are many different cohorts within the larger FP community that prioritize different things.

If I had to criticize your purity-centric flavor, I'd say it's very reminiscent of the height of the OOP craze, with algebraic terminology elitism being similar to the one surrounding GoF pattern terminology. Also similar are the grandiose theories of maintainability, and the dichotomy between what loudmouths preach and what code in the wild looks like.

People log things from .map callbacks. They don't grok monads. It seems entirely arbitrary to me to deny the functionalness of some code based on some technicality (case in point, do you avoid promises and do you Object.freeze(Object.create(o)) all your objects?)

IMHO, there's no point defending some notion of an FP brand. Looking around this thread, you can see that people already view React's hot take on FP as problematic. Same goes for general perception of the more elitist corners of the FP community.


I can agree with most of what you are saying. My alarm stems from the fact that a lot of developers' understanding of FP these days comes from their React experience (which they mistakenly believe is FP) and a lot of these developers also believe that OOP is now obsolete... all based on their mistaken understanding of what FP is. I think there is a need for course correction here.


> There is nothing functional about React.

There is literally an example React component in that article that the author calls "pure and referentially transparent". How can this be if there is "nothing functional about React"?


But how many React components are that simple? Almost none.


> Imagine for a second that a Promise's .then is called .bind, put it in a thunk if you want to be extra precise and tell me what it is. Hint: It starts with "M" and it's just a monoid in the category of endofunctors.

I think many of us familiar with the FP inspiration for language features like Promise also understand that it’s a Monad. But this is a weird response to a comment about the oddity of throwing a Promise. I may be mistaken, but it seems unusual (in the FP analogue) to return an Either<Future<B>, A>, and even weirder to obfuscate that in a seemingly synchronous interface to trick you into thinking you’re returning A | B.


> this is a weird response to a comment about the oddity of throwing a Promise

which actually has nothing to do with functional programming, it's just sloppy programming

This is because this person is one of those clowns who learnt one thing about functional programming and use that in every conversation to deflect criticism without much understanding of the criticism

> Imagine for a second that a Promise's .then is called .bind, put it in a thunk if you want to be extra precise and tell me what it is. Hint: It starts with "M"


> which actually has nothing to do with functional programming, it's just sloppy programming

I’m really cautious to agree here. We’re talking about something that’s increasingly core to React’s design (you don’t throw Promises yourself, the internal APIs do, and it’s documented that way so other libraries can interop). It’s a weird design but I don’t think I could call it sloppy.

> This is because this person is one of those clowns

This is also unhelpful. I hope we can get better at critiquing without attacking the person, even where we disagree with them.


> I don’t think I could call it sloppy

Instead of comming up with new API they retrofit existing one (the render function) to add continuation passing. They use throwing and promise, neither is for continuation passing.

Somewhere in this thread there is a link to the crankjs article which does the same thing using a generator-based API. It is also weird from a conventional point of view but at least simpler and somewhat more intuitive

> better at critiquing without attacking the person

How would you critique an attitude (pretentiousness and unhelpfulness) without attacking the person? This is a shitty trait and you have it but do not feel offended?


> Instead of comming up with new API they retrofit existing one (the render function) to add continuation passing.

It probably helps to understand why they made that choice. I’m not going to go deep into archeology to do that, the likely reason has been a central of several front page articles recently: color of function.

Generators, like you mentioned, can solve this without infecting the whole stack, but it’s probably breaking for a lot of tooling. Async function components are almost certainly out of the question. They probably carefully considered the options and found this pattern unusual enough and identifiable enough to not break the world.

I don’t like it or agree with it. I think it’s really weird. But I can understand how it could happen.

> How would you critique an attitude (pretentiousness and unhelpfulness) without attacking the person? This is a shitty trait and you have it but do not feel offended?

I don’t understand the question. You’re presupposing personality traits where many other things may be contributing. I struggle to communicate a lot of ways, and one of my biggest challenges is actually having my person dismissed or being afraid that will happen. I hope this discussion has given you enough context that you don’t think I’m a clown, now or in any future interactions. But now I can’t know if you will unless you say so. Even though I’m just engaging with you as sincerely as I can.

This, on a scale of every internet interaction, can prevent people from learning or even contributing. Even if they’re talented or otherwise open to learning and have a lot of unrealized potential.


Hey i agree with you, just want to be clear it’s not you i’m calling a clown. It’s the person with the monad comment. I should not call any one a clown, but i think their noise makes it harder for people to parse useful information on the internet, especially beginners actually. That must be called out one way or another.


Yeah, but if you are opposed to functional programming (or opposed to exposure to any new programming paradigms) of course you’ll hate the library that has had perhaps the largest impact in bringing concepts from functional programming into the mainstream. That’s perfectly understandable. But I like functional programming and I very much like React’s impact in this area.


Using Functional Paradigms in a FP language. Cool! All for that.

Bootstrapping pseudo FP styles into a Prototype Language with no types (JS is technically not OO, even `class` is just prototype sugar). Please no.

I really like concepts behind FP. I have tinkered with Haskell and gone through Bartosz Milewski's Category Theory material. That said, its radically different than traditional Procedural or OO coding. It really needs language level support to be useful, and that usually starts with types and the compiler. Open up "FP" libraries in non FP languages, and you often discover its just the same objects as the rest of the language.

That said, immutability is awesome. The concept of creating mutability boundaries and only exposing immutable data to external services and clients solves a whole class of bugs related to "who changed that?"


Yeah, I started going "well, time to look at the rest of the ecosystem for the Next Thing" with Hooks.

Given requirements that meant, to progress, they were going to need to either:

1) Tell devs that sometimes they would simply have to use classes/objects for some components, because certain performance enhancements or state-management would only be available there, or;

2) Partially re-implement objects with really bizarre declaration syntax, in a language that already has objects—shit, its functions are objects, and maybe it's changed but I read the hooks code when it was added and it was just some FIFO property/method queues, rather than tables, tied to a damn object representing your component in React's core state-machine;

They chose #2.

[EDIT] yes I'm aware that one reason they prominently gave for hooks was that inheritance hierarchies could cause problems in React codebases, but that seems woefully insufficient as a motivation for writing a crippled version of objects/classes that lack the features they had problems with, rather than just telling people "maybe stop hitting yourself?" and continuing to use what the language already provided, which everyone already understood.


The thing that blew my mind was React gave a decent abstraction for externally set values vs internally managed values in props/state. And then the community immediately declared State as evil, and boiled the ocean to replace it.

All UIs need state. Yes state is bad in most cases and makes programming harder. No abstracting it into 4 different files doesn't make it any clearer.

There was an issue with composition in React. HOC didn't scale very well, and Inheritance is almost always Bad (TM). That said, I do think hooks were an esoteric choice versus a more explicit service registration/DI pattern.


> Throwing Promises for Suspense is basically Algebraic Effects

I wish Dan Abramov hadn't made this analogy[0], they're nothing like algebraic effects. The core idea behind algebraic effects is more similar to something like dependency injection if it was generally possible to "deasync"[1] things in JS, except it leverages dynamic scoping instead of lexical scoping. The Suspense thing is closer to those jokes where the punchline is something along the lines of the programmer saying "have you tried to restart it?"

[0] https://overreacted.io/algebraic-effects-for-the-rest-of-us/

[1] https://www.npmjs.com/package/deasync


> I wish Dan Abramov hadn't made this analogy[0],

I bet it wasn't Dan who came up with this analogy. My bet is on Sebastian: https://twitter.com/sebmarkbage/status/941214259505119232


Further evidence of this in this blog post by Dan Abramov https://overreacted.io/algebraic-effects-for-the-rest-of-us/


> Then it was infected with all sorts of Functional Programming paradigms grafted on top of Javascript.

Except it is not really functional. See:

https://mckoder.medium.com/why-react-is-not-functional-b1ed1...


I think it's alright, the real problem that I've noticed is that a lot of developers tend to misconstrue what they need and bloat their projects in amazingly unmanageable way because it 'the way to do things according to random source x' which could be some weird abuse of state management systems like or redux or general application design

FWIW I've seen it in many projects outside of the react/js world as well

IMO there's been a general drought in books/material on reasoning/thinking about software in general in-favor of the framework/library centric mania we have now which focus on the least interesting aspects of the field -- the cynic in me thinks this is due to how we hire people but there's likely more to it than that


1) New fast, easy framework bursts into the scene.

2) "Hey it doesn't work with edge case X, let's graft on more features to cover it"

3) Repeat step #2 a few dozen times

4) The framework is now neither fast nor easy, invent a new one and go to step #1


I have found that Redux Toolkit solved most of the pain with vanilla redux.


There is nothing wrong with functional programming. It's a bit sad that redux and hooks give it a bad rap. Those things are NOT functional programming.


You'd be correct, it's a really unfortunate design decision. The author of CrankJS has a full critique here. https://crank.js.org/blog/introducing-crank


I thought so too for a while, but after using concurrent mode a bunch I came to agree that the usecases it’s built to support (rendering fallback UIs while async processes occur) actually do belong as first class citizens in the framework. It’s the kind of this you implement yourself over and over again. And often the async processes you’re waiting for are React components themselves to load and parse. I’ve come to like the implementation too. I’m glad to see it mature and I like how they’ve taken their time with it.


Do you mean with React.lazy? Suspense hasn’t been used yet outside of that in released versions of React. Would be curious what specifically you ran into though; it shouldn’t make errors hard to debug.


Suspense is a pretty weird step into "magic" for a library that has been a pretty damn thin layer on top of JS for so long, I fully agree with that. Using it is somewhat pleasant in terms of terseness, but very unpleasant for the fact I do not have a good understanding of how the lifecycles of the async resource(s) influence the render schedule, which is really the core of React from my perspective


> weird step into "magic" for a library that has been a pretty damn thin layer on top of JS

I mean, hooks are totally this. They fundamentally break the concept of a "function" despite calling them "functional components." They use this weird notion of state (i.e. magic). The best way I can describe it is a cousin of dynamic scoping from the bad old LISP days. Back before lexical scoping was invented. So you end up with all these caveats and gotchas. Go look up useRef with useEffect and useCallback. It's all a total clusterfuck.

The lifecycle methods weren't perfect. But at least you could understand them. But I lost a lot of respect for React way back when they started fussing with the lifecycle API, a year or two before hooks. Their vDOM abstraction was starting to leak heavily and they were struggling to make sense of it.

When people say they like React, I really suspect they mean they like JSX. React, itself, is a mess. Always has been.


They’re called “function components,” not “functional”, because they reside within a JS `function` as opposed to a class.

The word you’re looking for is side effect. The `use*` family of functions operate as hooks from the component into the renderer, so the renderer can easily see what dependencies a component has. This is accomplished by producing side effects.

The lifecycle methods are all well and good but there was an ergonomic problem with them with shouldComponentUpdate. No one wants to implement that function by hand when it involves whitelisting all props you want to produce a rerender, which is most of them. People would always write bugs. It’s much easier to create a list of dependencies a la second argument to useEffect.


> They’re called “function components,” not “functional”

They've been calling them functional components forever. https://github.com/facebook/react/blob/main/packages/react/i... I'm not sure why you're being a language nazi here. It's beside the points I was making anyway.

> The word you’re looking for is side effect.

Enough with your patronizing. Obviously it is using side-effects. That's the entire point I was making. Functions (as in the term from "functional programming") do not produce side-effects. Functions do not contain state. You know what is good at containing state? Objects. The whole paradigm of an "object" is exactly what React is trying to do with functions. It's nonsense. You can't call a hook function outside of React's apparatus. When React calls one of these hook functions, it has to dynamically switch out the context. Which is where my analogy to dynamic scoping comes from.

> an ergonomic problem with them with shouldComponentUpdate. No one wants to implement that function

Yes, well, as I said React has always been a mess and there are just as many problems with useEffect. Throwing out the entire API is just dumb. Libraries are no longer universal. You have to consider whether it's using hooks or not. Especially since they never formally deprecated lifecycle methods. They just shrugged their shoulders and went "here's hooks, use them if you like them."


`StatelessFunctionalComponent` is not something that's publicly exported, at least from `"react"`. The convention is to use the `React.FunctionComponent`, or `React.FC` annotation.

> Functions (as in the term from "functional programming") do not produce side-effects.

This isn't true, even in the so-called "functional languages." Calling a function in Clojure could produce side effects, and the same is true in Haskell. In Haskell, calling a function that produces a side effect would necessarily return an IO monad, but that's a separate concern from whether the function invocation caused the side effect.

> Libraries are no longer universal. You have to consider whether it's using hooks or not.

You almost never have to think about this. Either a library provides hooks or it provides components. If it provides components, they could be implemented using the old component-style API or using function components; I have no idea, and it's irrelevant unless I plan to fork the library. Conversely if the library provides only a hook, I can easily wrap it in a thin component layer if that's the interface I prefer. The libraries are therefore effectively universal, since there's nothing that says I can't use a hook-based component within a function component, or vice-versa.


> It’s much easier to create a list of dependencies a la second argument to useEffect.

Even easier to just not do that, either, as in Solid’s version of hooks.


Honest question, is what you’re referring to this[1] or something else? I’d be interested to see how hooks could work without side effects.

[1] https://github.com/ryansolid/component-register-hooks


> Honest question, is what you’re referring to this[1] or something else?

I’m talking about Solid, the web framework, which has hooks (they call them “effects”) similar to those in React, but which do not require explicit dependency lists when specifying them.

https://www.solidjs.com/tutorial/introduction_effects


Thanks. I don't understand how it's better though, wouldn't you need to start following the Rules of Hooks for this data retrieval (`count()`) as well, lest the renderer not know what all your dependencies are?


I think this is a case of to each their own.

I find hooks provide a far more declarative, testable, predictable developer experience. The simplicity of useEffect, useCallback, useRef, etc. makes it so I know exactly what I need to reach for when I need to accomplish certain things.

It can get complex, but I find that usually means you need to back off and rethink things.


> I mean, hooks are totally this. They fundamentally break the concept of a "function" despite calling them "functional components." They use this weird notion of state

State and React have always been fundamentally intertwined, so I'm going to heavily disagree with the claim that hooks are a new magic wrt React. Personally, as someone who has used React for a long time, hooks have been a very intuitive and terse new syntax to use the lifecycle hooks & provides a far superior way to deal with state machine transitions.

> Go look up useRef with useEffect and useCallback

I must say, as a pro web developer who has built loads of applications, including model editors, charts with React views on top of D3 math, interactive 3D renderings, graphs, you name it, I don't know why I would have anything to do with "useRef with useEffect and useCallback". I've never encountered any issue with these things. What use case are you trying to solve that requires those hooks and what issue with those hooks exists that is blocking you?

> I really suspect they mean they like JSX. React, itself, is a mess. Always has been

Oh, you just hated React all along, so you probably never understood it. Easy to see why you don't like it then.


> why I would have anything to do with "useRef with useEffect and useCallback". I've never encountered any issue with these things.

The fact that you are asking and haven't hit the issue suggests you haven't actually used useRef before.

> Oh, you just hated React all along, so you probably never understood it.

Sure, asshole. I've only been using React for 6 years now. But whatever.


[flagged]


I actually did not downvote you anywhere in this thread.

> I have useRef and useEffect all over my codebases, I have never used useCallback though

useEffect has the caveat that it won't update with useRef. On the initial mount you will probably be fine (because useEffect triggers after first render). But if your component is unmounted (or remounted), then useEffect will not trigger leading to bugs. Which can be quite severe, such as memory leaks. [1]

But my point isn't about useRef. My point is there are lots of these types of footguns with hooks in general. And when you hit one of these, you bang your head on the wall until you find someone had the same issue and wrote it up on their blog or stackoverflow.

[1] https://medium.com/welldone-software/usecallback-might-be-wh...


> useEffect has the caveat that it won't update with useRef

Hey, what do you know:

> My guess from your tone and general confusion around React is that you expect useRef to have lifecycle hooks when the `current` value changing does not have any lifecycle hooks at all, and somehow your problem with that has made you rail against these hooks

Ok, but I'll allow your point that "hooks are complex". What do you propose as an alternative? Have you seen a superior solution the React team is just ignoring? From where I sit, hooks are very terse, they have well defined rules, the error messages they give are useful, and they do a lot of powerful things.

Powerful things have edge cases, and your edge case was assuming something would be magically wired for you. Even the instantiation of a `useRef` vs a `useEffect` should give big clues useRef won't update a useEffect; the "touch point" for the useEffect getting the updated values is thru the React component, which has two well-defined stateful flows: state and props. `useRef` is quite clearly (by definition!) neither of these things, and no wiring has ever existed causing any type of ref to re-update your component (and they importantly never have).

So, sure, there are limitations and rules you have to pay attention to with hooks... but that's just programming. I don't care that someone accidentally created a memory leak by misusing hooks, you can do all sorts of powerfully broken shit when you don't take effort to misunderstand the underlying library. Hell, I cause my browser to crash semi-regularly when developing in mobx because I cause reactive infinite loops, does that mean mobx is a shit tool and I should stick with redux?

Edit: even further to this point, did you read the god damn docs for `useRef`? https://reactjs.org/docs/hooks-reference.html#useref literally addresses this caveat you're bitching about EXPLICITLY. "Keep in mind that useRef doesn’t notify you when its content changes", how could it even be more clear no consumer will be notified of updates to your ref?


> What do you propose as an alternative?

There are lots of alternatives, but perhaps the simplest would have been to use async generators. This is how Crank[0] (mentioned elsewhere in this thread) works, and it allows you to do anything (AFAIK) that's possible with hooks with a much simpler and more testable API.

> So, sure, there are limitations and rules you have to pay attention to with hooks... but that's just programming.

No, it's not. The biggest problem with React hooks is that they are not composed of transferable knowledge, meaning memorizing these rules and patterns does not transfer outside of React; likewise, I can't use much of the knowledge I have already built up over many years of my career when using hooks. It's the same argument that's made against Rails, where you have to learn tons of Rails-specific idioms (on top of having to understand general concepts like relational database access patterns) instead of just writing code in a way that's more direct and intuitive for anyone.

My brain has limited RAM. The more things I have to keep in my head when developing against an API, the more likely I am to make a mistake. With every release of React, I seem to have to keep more and more of these details in my brain as I work. Contrast this with something like Svelte, where you really only need to fully grok about two concepts to use it effectively. I understand that this is the tradeoff the React team made, but I'm not convinced it's worth it.

[0]: https://crank.js.org/ and https://crank.js.org/blog/introducing-crank


> perhaps the simplest would have been to use async generators

Honestly, I'm going to be hard-pressed to not give a sarcastic answer to someone proposing "async generators" as "the simplest way to manage state". They are not popular, thus they are not transferable, and I cannot imagine why I would want to use a library which advertises race conditions as a feature when managing complex application state


> They are not popular, thus they are not transferable

I'm not sure that tracks. Async functions are extremely common, so that can't be it. Generators are less commonly used, but are a relatively simple language feature (also present in other programming languages besides JS) that you can freely use outside of the context of the framework.[0] It's not a big leap to put the two together. Writing and testing an async generator doesn't require any framework-specific incantations.

Anyway, I just used Crank as a single example of a possible alternative to React hooks—there are plenty of others that have been suggested. In fairness, it is a complex problem, but other frameworks such as Svelte have solved it in a way that puts much less mental burden on the developer, so it's not like better alternatives don't exist.

[0]: As an example, at my last job, we used redux-saga to maintain some parts of our high-level state, so we were already making heavy use of generators. It would not have been a very big leap to then start using generators in our components.


> Generators are less commonly used, but are a relatively simple language feature

Generators are basically unused, full stop. I would go so far as to argue that no major JS library uses generators as a first class concept. I would go even further to argue that proposing a very unpopular control flow technique as a method of state management sounds like the #1 way to cause a library to have a steep learning curve and result in unexpected interactions, especially when being contrasted to algebraic effects.

Hooks and algebraic effects lean into the core concept of React as a "pure" functional view layer on top of application state. This is one of React's strengths, and it furthers it by ensuring your components / functions have graceful mechanisms to handle events both of the state change variety AND, as before, user / DOM change type via hooks. It also allows for terse invocation and easy reuse. Enough about this transferable business, writing a reusable pure function is as transferable as it gets.

I really don't know what mental burden hooks are putting on developers either. It's pretty simple: you call the same hooks in the same order every time you render your function. There's not that many of them to use, and you don't need all of them by any stretch. All the gotchas that exist already seem like gotchas related to first-class React concepts like state and props and were existing in class components but in a different syntactic sugar.

I think we can probably conclude here, because obviously as a fan of React Hooks who thinks they solved a ton of issues in React (to the point I rewrote & improved my entire component library with them), I don't see how using unrelated solutions that require learning entirely new concepts not popular in the domain already will improve the situation.


> I would go even further to argue that proposing a very unpopular control flow technique as a method of state management sounds like the #1 way to cause a library to have a steep learning curve and result in unexpected interactions, especially when being contrasted to algebraic effects.

Putting aside the fact that hooks are not the same as algebraic effects, I think it's funny that you believe algebraic effects are simpler to learn and reason about than generators. I'll grant you that it's pretty easy to get up and running using hooks, but I've met few frontend engineers who could actually explain to me the entire lifecycle of a complex functional component in detail. You can argue that those are not very good engineers, but I've seen this far too often not to blame the tool.

> Enough about this transferable business, writing a reusable pure function is as transferable as it gets.

But they're not pure! As soon as you call `useState` or any other hook, you lose all semblance of purity in your components, because the functions are now tightly bound to the React life cycle and can't be called or tested in any way without that context. Debugging and testing hooks means using React-specific tools that aren't applicable anywhere else, and stack traces become significantly less meaningful than they were with the class-based lifecycle methods.

> I really don't know what mental burden hooks are putting on developers either.

The "rules of hooks" are weird and counter-intuitive, and necessitate a lot more care with what would otherwise be simple refactors. That said, I could grant that it's not a big deal if that was the only gotcha, but hooks are full of them. For instance, I can't tell you how many bugs I've encountered related to the dependency array passed into `useEffect` and `useCallback`—it's very easy to have your component render too often or not often enough in ways that are not immediately obvious in a code review. Finding bugs related to these dependencies can be really painful, whereas class-based components let you easily debug updates by plopping a breakpoint into `componentDidUpdate`.

> I don't see how using unrelated solutions that require learning entirely new concepts not popular in the domain already will improve the situation.

Yeah, I think we can agree to disagree here, because this is exactly what I think about hooks: they are React-specific magic functions that require learning entirely new concepts that are meaningless outside of React. To each either own.


> they are React-specific magic functions that require learning entirely new concepts

But they don’t, they’re the same concepts as React always exposed. It literally took no new conceptual learning for me to refactor my entire component library (including forms to graphs to zooming panning charts) from mobx / old react state! It’s a more honest representation of React than the old setState business by a lot


Pretty damn thin layer? The language with its own syntax and build tools? The one with JSX?

React is one of the thicker layers I've seen.


I think it could be argued to have been, at times, conceptually thin, if you like.

I agree that the tooling and even React itself, under the hood, have never been thin, or if they ever were it was only very early on in the project. Well-functioning enough that one could forget about them at times, maybe, but not thin.


Oh no, JSX that compiles down to the exact set of `new Object` calls you would expect in a tree structure, how can I understand such complexity!?

Really, you're kidding yourself if you think React isn't far simpler than Angular or Vue or any of these other frameworks. If you have some different direction in mind, fine, but I doubt it scales


Don't misunderstand. I like JSX. However, that doesn't compel me to call it thin.


I find that strange. For example, I would call Angular or Vue "thick" with their extra templating files and DSLs and two-way binding.

I would call React thin because the JSX components you build are transparently just objects, they interact with types super gracefully because components are just classes with a method that returns nested objects, and your code is just invoking JS and producing JS until the React library itself performs the side effect of rendering.

I understand that React has abstractions and a heavy scheduling engine and all sorts of complexity, but a React component - the core concept of React - reuses directly JS concepts in place of introducing its own in most situations. That is thin.

I admit that if you are just thinking of libraries in general, of course a frontend framework is not "thin", but for a library which enables true composability and reuse, React is so thin compared to is competitors. Which seems a reasonable de facto context for a conversation about React.


I don't think it's thin even in that context. For example, invoking a hook comes with a bunch of rules beyond "just javascript". You shouldn't invoke a hook conditionally. You shouldn't invoke a hook in a loop.

I've run into state/props mismatches due to the diff resolving differently than I thought it should. It's possible to solve this, but it further breaks the illusion of a thin layer.

Maybe it's a different way of thinking, but I don't think two-way binding is inherently thicker. To me, thickness is related to the amount of "mechanism". A handlebars-type templating system seems much thinner to me.


Suspense, itself, is somewhere in the range of “uninteresting” to “neutral”, in my opinion. Its direct use case would probably have been better solved by:

1. Providing a general signal to reuse the existing DOM node (or subtree, but that’s less useful) without performing any render logic.

2. Allowing components to use built-in suspension semantics (generators, async/await).

The former would have other really useful applications, like partial/selective hydration. The latter is closer to both the language and the original spirit of React, which embraced being close to the language. (Who ever thought “throw a Promise” for meaningful control flow before this?)

That said, it’s pretty clear from what React team has discussed since Suspense was introduced that it’s part of a larger strategy. Specifically: React Server Components. They’re laying the groundwork for that now, in stabilizing Suspense SSR.

I’m more interested in a less sophisticated solution, but it’s pretty clear RSC is both where React is heading and requires a more opinionated foundation like Suspense.

> difficult-to-track-down ways because of how errors are propagated with suspense

I suspect this has more to do with concurrent rendering generally, than with Suspense itself. Debugging concurrency is harder in general. React's simplistic top-down rendering model was successful in part because it was simplistic and top-down.

- - -

All of that may not be justified for your needs! React is positioned for a very specific set of use cases (even if it’s over-used for similar-looking ones). You may find you’re more comfortable in a more simplistic VDOM (and that’s okay!) or a library based on reactivity (if so, and if you’re coming from familiarity with React, I’d suggest giving SolidJS[1] a look; its rendering model is much closer to the DOM).

I’ll also mention that I’ve spent more time with Preact than React, and have found its Suspense implementation much easier to work with and debug.

1: https://www.solidjs.com/


I'm pretty delighted by a lot of the concurrency stuff that's popping up.

At this very moment I'm wrestling with a UI where the left side is a list of cartographic datasets, and the right side is a rich OpenLayers preview renderer.

I want the right side to be "low priority" where it tries to render a preview, but is happy to abort or not get done in-time if the user selects a different dataset. At the moment, the processing acquiring and rendering the preview makes the rest of the UI a bit laggy.

I suspect a good bit of my custom code can be replaced with some of this transition stuff.


You issue is likely due to a heavy computation blocking the main js thread (rendering). In this scenario the suspense api will not solve the UI lag. I've had the exact same pattern with a home build markdown editor where the right side preview should render quick, but lag behind if too heavy and give priority to left hand side. I tried the alpha and speak from my own experiences, you'll have better luck by offloading render computations to a background web worker. The preview can do a 1 time synchronous render, cache the result in it's local component react state, then all future state updates are computed async on the background thread. Main thread left unblocked


The problem comes when the rendering itself is the bottleneck. You can't put that on a Worker because it's so entwined with the DOM. We ran into this several times at a past company where our UIs rendered elements in the 10s of thousands, and we had no real recourse except to optimize everything to death (and things were still laggy). In one case we implemented our own, bespoke, crappy equivalent of suspended rendering and it was a mess but it was just barely worth it because we were so desperate.


In my case the right hand preview being generated is literally HTML that is presented as formatted markdown. The solution for me was to detach the generated markdown html tree from the creation of the react elements. You can have the worker return a json tree shape that defines all the elements it wishes to place onto the dom, ships it over to the main react element that React.CreateElement's through the tree.

This way the cached elements can be shown until the new tree elements are created and you can just react setState to the new elements and it's instant


Right, so you're offloading the markdown processing but not the actual React render logic. Reasonable enough for this case, but doesn't translate to the majority of scenarios.


> We ran into this several times at a past company where our UIs rendered elements in the 10s of thousands

Maybe that's the real problem? If at all possible, such intensive tasks should be done in native frameworks, not web technologies. Alternatively, why not simply do less? Pagination, extracting separate sections of the app into separate pages/views and many others are perfectly valid approaches to something like that in my eyes, not just turning to low level optimizations.


We had various project constraints and user demands that made most of those suggestions untenable. We used pagination in some places, but in others our users refused to accept it (they wanted Ctrl+F, fast browsing of huge datasets, etc). Writing a native app would have been miles outside the realm of possibility (we had a small team making a very complex product, none of us had native app experience, we needed to support multiple platforms, we specifically needed instances of our server to be able to serve up their own GUI, we needed to be able to interface with them from arbitrary remote machines without installing new software, etc).

To use the words of a commenter in another thread: I didn't provide sufficient information for informed responses. It was just a general comment about why I'm excited for React 18 to help better manage concurrency in a number of ways.


It's considerably more complex than that. There's just a lot of stuff that gets compiled and rendered. No single part takes more than a few milliseconds, so I can bin it across many tasks.

Picture a canvas that I'm calculating then drawing tens of thousands of elements to before displaying it. Very binnable. Very hard to get right to a point that you can't "feel" the lag when working with the rest of the app.

I also explored web workers but it's currently more hassle than I want to be bothered with.


If your use case requires rendering and updating thousands of components, maybe React wasn't a good fit?

You could try switching to Preact which has better performance and should be painless.

https://krausest.github.io/js-framework-benchmark/current.ht...


Not components. Elements that compile to a canvas. Think tens of thousands of points, lines, polygons, all drawn as vector or raster images. Ie. compiling a deeply rich interactive map of data.

I appreciate the advice but I didn't provide sufficient information for informed responses. It was just a general comment about why I'm excited for React 18 to help better manage concurrency in a number of ways.

Suspense will also be nice because I can eliminate a lot of my own "loading screen" logic.


> Not components. Elements that compile to a canvas.

Ah right. I thought the canvas example was just an example.

Still, a faster framework would be better for high performance use case, no?


I know you said you are not expecting informed suggestions but it got me thinking of another solution that has not been proposed. If the right ui is low priority and you want to unblock the left window's thread then maybe just a iframe for the right side would separate the work loads completely.


I have been really annoyed by a recent change in React dev tools. Have you seen this? They hijack browser's console.log method, and report all logged messages as coming from react-dev-tools. Very useful for console.log debugging!

Link: https://stackoverflow.com/questions/69071151/why-is-console-...


Any discussion of NextJS and how it would work with the new SSR technologies?


Not sure how NextJS handles async component SSR, but looks like from the docs we should just be able to use React.lazy in place of loadable-components in an SSR render pass now. The new server components seem to be a different feature not directly related to regular SSR usage. I think they added that for people who aren't using GraphQL for data-fetching, so that certain components can be rendered on the server only and set in a serialized form without sending the associated JS required to render it.


I like the way they describe SSRs , then talk about hydration - which of course has to lead into interesting videos on compressed towels , and peat pellets!


I haven’t used React in a while, what does it offer that WebComponents do not?


Webcomponents are a huge mess, caused partially because it requires to do (some) composition in html. React is much simpler, it uses basic html elements (div, input, ...) and event apis to compose an application in javascript.

These are some disadvantages of webcomponents that I can think of.

- Can't register multiple versions of a webcomponent. Let's say you are using "x-dropdown"@2.0.0 which depends on " x-icon"@2.0.0 and "x-menu"@3.0.0 which depends on " x-icon"@1.0.0. Your app will crash because html tags can't have multiple versions ("x-icon" 2.0.0 and 1.0.0). It makes handling big projects a nightmare. And there are name collisions too.

- Not all properties can be serialized into attributes as strings, so you end up just binding properties. Boolean attributes have special are weird when used in the javascript side (an empty string is treated as a boolean)

- The shadow dom can be too restrictive and inflexible. Implementing portals for instance, requires using ugly hacks that depend on your webcomponent framework.

- Some complex webcomponents are not interoperable among different frameworks.

- Static analysis on webcomponents is poor and fragile. Compare declaring types of events in webcomponents, to declaring types of event handlers in react.


Youtube's website is built with web components (used to be Polymer, but I wonder if they haven't migrated to lit by now). Seems to be working fine for a large-scale project like theirs.

Chrome Dev Tools are also, at least in part, built with web components.


> Seems to be working fine for a large-scale project like theirs.

It's not web components that were working for them at scale, but Polymer.

They would've probably nebver completed anything with Web Components alone due to how horrendously bad their API is. You can compare Web Components API and Polymer API here: https://twitter.com/dmitriid/status/865518972380237825

It still took them over two years to switch from Custom Elements v0 to Custom Elements v1.


It doesn't drive you mad with a needlessly complex syntax/API for one.

Also no browser vendors that flat out refuse to implement parts of the spec (Apple [0]), or block proposals unless implemented in a highly specific way (all, here's one example [1], ugh politics).

[0] https://bugs.webkit.org/show_bug.cgi?id=182671

[1] https://github.com/WICG/webcomponents/issues/587#issuecommen...


It's 2021 and we still can't define custom tags in html (without js) :

<template tag="test"><h1>works</h1></template> <test/>


is= is dead, and Safari had good reasons for it. On mobile, so can't quickly find the rationale.

But it's the same rationale IIRC why built-in components are not extensible (even if this was one of the original promises): the browser has no way of knowing about the actual behavior of the object, which leads to all kinds of mess inside the engine.


So many other parts had to be done in a specific manner or left out entirely to get committee consensus, yet this was written into the spec even though Apple has opposed it from the beginning.

The validity of Apple's reasoning makes it even stranger.


Yeah, the whole thing about Web Components is weird. And is getting increasingly weirder.

Quite recently Constructible Stylesheets were released in Chrome:

- because lit wanted them

- despite Firefox and Safari being against the state of the spec

- despite Safari clearly stating they are not going to implement the spec, ever (there was a trivially reproducible race condition in the spec)

The entire discussion here: https://github.com/WICG/construct-stylesheets/issues/45#issu...


In my experience React, despite its complexity, was always far simpler to use than WebComponents because it has clearer documentation and established patterns. I'm sure WebComponents can do everything React can do, but they do not have anywhere near the ecosystem and developer support you get with React.


There is this article (https://dev.to/richharris/why-i-don-t-use-web-components-2ci...) by Rich Harris, creator of Svelte which explains pretty well why he personally doesn't use web components.


I feel like everyone has the wrong idea about web components. Perhaps it's in the name. There's no "WebComponent" class on the window object, but there is an HTMLElement you can extend and a `window.customElement` registry for tagName invocation, a thing called a shadow root, and so forth. Those are all things that I am glad exist. If I thought of them grouped together as "Web Components" and compared that to components in frontend JavaScript frameworks then yeah, I guess I'd be disappointed. Otherwise, the people who say they "don't use" web components are being as unreasonable as it would be to say to not use the `<video>` element because it doesn't support all the things that `<canvas>` does with some 3rd party library for compositing.

Custom elements are awesome for small things that don't need to appear in an SSR context (assuming you're using shadow DOMs). No, they don't support composable stylesheets, whatever those even are, but seriously, who really needs them? If what you are doing is complicated enough that the browser's native APIs are too obtuse then yeah go for something like React or Svelte. No matter what, there's going to be something that someone's JavaScript library is going to do better than the browser. I'd use uncommon browser and language features if they made sense for a task.

The `<template>` and `<slot>` elements are really dopey and hard to understand. That's where something like React or Svelte comes in. Nobody would use either of those libraries if they didn't have better templating than the browser.


> I feel like everyone has the wrong idea about web components.

What is the idea behind Web Components? Does anyone have an idea of what they are, should be, and where they are going? They've been around for 10 years now. Google has poured literally millions of dollars into trying to make them happen.

If people still "have the wrong idea about web components", it's a testament to their failure.

> Otherwise, the people who say they "don't use" web components are being as unreasonable as it would be to say to not use the `<video>` element because it doesn't support all the things that `<canvas>` does with some 3rd party library for compositing.

Well, no. People who say "don't use web components" are very much aware about the fact that web components:

- at the core are 4 different standards. One of them is already fully deprecated (HTML Imports). The other one already has a deprecated and removed version (Custom Elements v0)

- introduced so many problems by simply existing that Google (primarily Google) has been pumping out literally thousands of pages of new specs just to fix the problems that web components created.

Problems: https://dev.to/richharris/why-i-don-t-use-web-components-2ci... and https://news.ycombinator.com/item?id=28697664. And new specs? Oh, they are introducing their own new problems: https://news.ycombinator.com/item?id=28698563

- have an API that is both too high level and too low level to be usable.

It's too low level and too verbose, so after several years of promoting them as "the be all end all components for the web" the narrative shifted to "it's just an API for library authors, you're not supposed to use them by hand". It's unusable at any significant scale. Google's own AMP has switched to using Preact to author their components because they couldn't bear it anymore.

It's too high level, so in the 10 years of its existence there are hardly any libs and frameworks that have adopted Web Components as the foundation. And even the new ones tend to skip Web Components. Well, most libs and frameworks can compile to Web Components, and can consume Web Components. But hardly any framework actually uses them as a foundation.

Well, I've linked to the dozens of problems that they introduce, so no wonder.

- "Custom elements are awesome for small things that don't need to appear in an SSR context"

that don't need an SSR context, that don't need a11y, that don't need to split SVGs, that don't need...

Too many "don't needs" for a tech that has seen millions of dollars poured into it, and 10 years of development. After all that it's still "it's awesome for small things". Only for small things.

Meanwhile, w3c has unveiled its own design system here: https://design-system.w3.org It uses SASS and it uses a third-party library to, quote, "enhance a <select> into and accessible auto-complete via JavaScript."

Imagine if millions of dollars and countless man-hours poured into Web Components were instead directed to make CSS better, to enhance the crappy built-in controls etc.? Oh, you'd have a better web, and not an "awesome for small things with dozens of problems".

> No matter what, there's going to be something that someone's JavaScript library is going to do better than the browser.

Ah yes. I remember someone calling jQuery "the disappearing framework". Because its eventual goal is to be fully replaced by browser APIs.

It looks like Web Components' motto is "there's always someone doing stuff better in Javascript, so why bother, let's be crap".

> Nobody would use either of those libraries if they didn't have better templating than the browser.

Nope. People are using them not because of templating alone.


> If people still "have the wrong idea about web components", it's a testament to their failure.

In a way, that's exactly my point. I don't get the need to view the related technologies as "web components". It's a branding error made to look niche features sound like something more than they actually are.

> It's unusable at any significant scale.

It's a fallacy to denigrate anything on the basis of scale, because not everything has to be at "scale". That doesn't have to be the job of web APIs. These tools exist to render things on web pages; they weren't intended to satisfy the needs of Google and their wannabes, as much as Google themselves believe otherwise (in seeing themselves as the arbiters of the web).

> Google's own AMP has switched to using Preact to author their components because they couldn't bear it anymore.

This seems like speculation. People switch projects to their framework of choice for any number of reasons, many of them not necessarily being objective. Preact is way cooler than custom elements, so of course there will be a bias towards using it no matter how useful or not useful custom elements are.

> Too many "don't needs" for a tech that has seen millions of dollars poured into it, and 10 years of development. After all that it's still "it's awesome for small things". Only for small things.

Again, not necessarily anyone's problem. Lifecycle hooks, templates, and shadow DOMs are missing features in a system where nodes can be inserted dynamically. Are they critical? No. Do they "scale"? Maybe not, but that's really not an argument against them being in existence. Frankly, I don't care if someone mistakenly thought they were a multi-million dollar idea.

> Well, I've linked to the dozens of problems that they introduce, so no wonder.

All of those arguments come from the premise that separate APIs are supposed to form something coherent. For one, I don't know how Chrome-only features are somehow supposed to be the fault of web components.

Custom elements are as inaccessible by default as non-semantic HTML elements. The use of ARIA attributes is pretty common for elements that are not custom.

If SSR is a problem then don't use shadow DOMs. If that's irreconcilable then use React or something that can scope CSS. Otherwise, a custom element can receive a role like anything else no matter what context it's rendered in.

> Nope. People are using them not because of templating alone.

That's not what I said. Templating isn't all that React and Vue do, but it's a make or break feature. Few would care about component lifecycle, reactivity, and other features if they had to verbosely hook into elements using regular JavaScript syntax. In particular, nobody would use Vue and especially Svelte if they had no templating. These "frameworks" are primarily templating libraries. React would have never taken off if there wasn't JSX.

> It looks like Web Components' motto is "there's always someone doing stuff better in Javascript, so why bother, let's be crap".

What exactly is the argument against that? HTML is crap, and for good reason. Browsers could have essentially become something along the lines of Adobe Flash, but instead they chose to be adequate for rendering pages. (some notable exceptions notwithstanding) Likewise, whatever "web components" are supposed to be, they add a few niche features to an existing system. Expecting bureaucratic web consortia to be wanting or able to compete with the likes of React is a path to disappointment.


> It's a fallacy to denigrate anything on the basis of scale, because not everything has to be at "scale".

Scale is "anything beyond the simplest of components".

> That doesn't have to be the job of web APIs. These tools exist to render things on web pages

Yes, that is exactly the job of Web APIs, and they are horrible even at rendering things on web pages. You'd have to search really far and really wide to find APIs that are as slow and as inefficient at putting pixels on screen like Web APIs.

But even beyond that, web components are a horrendously bad, overly verbose API that is unsuitable for, you guessed it, scale. Write a few of them by hand, and off you are looking for a framework or library.

> > Google's own AMP has switched to using Preact to author their components because they couldn't bear it anymore.

> This seems like speculation.

It's not speculation, but an overexaggeration. AMP project is pretty tight-lipped on the reasons why, but here's a big one: https://twitter.com/cramforce/status/1181927980467138560

--- start quote ---

The main issue was that handling attribute/children mutation got too complex when implemented manually instead of relying on diffing.

--- end quote ---

This is what I mean when I'm talking about scale.

> Again, not necessarily anyone's problem.

It is, ultimately, the problem of the people who will be using this tech.

> All of those arguments come from the premise that separate APIs are supposed to form something coherent.

No. All those arguments come from the fact that Web Components break all those things, are broken for all those things, and keep breaking a lot of other things despite everything that's poured into them.

And you can't just hand waive and dismiss all concerns with "who cares".

You have your project and someone brings a Web Component into it? Oops, your project can no longer be SSR'ed.

You have your project and someone brings a custom field into it implemented with Shadow DOM? Ooops, suddently your project has an inaccessible field.

And so on, and so on.

> The use of ARIA attributes is pretty common for elements that are not custom.

ARIA attributes do not cross shadow dom boundary. Web Components will break accessibility instantly just by virtue of existing (if they use shadow DOM).

> If SSR is a problem then don't use shadow DOMs.

Ah yes. "You're holding it wrong". That's the problem with web components: they break in so many common scenarios, that any other tech would be laughed out of the room. And yet, here we are, with people valiantly defending them.

> What exactly is the argument against that? HTML is crap, and for good reason.

HTML is crap, so let's add even more crap to it and be content with this crap?

> Likewise, whatever "web components" are supposed to be, they add a few niche features to an existing system.

That's the problem. The only features they add are "some niche features". The cost of developing, supporting and integrating these features has far surpassed any potential usefulness of these features. And their primary use case, still, is "yeah, maybe as some small dumb components if you don't use shadow dom, if you don't care about SSR, if you don't care about <a dozen other things that developers do care about>".

So what exactly is the idea of web component that everyone misunderstands?


React does a lot more than WebComponents. Primarily the reactive programming model of only updating subtrees whose props change, but also an entire parallel tree of state/context updates for propagating data that lives alongside the component hierarchy.


what does web component offers at first place is the real question. It's a spec but beyond that, Web Component doesn't really solve any of my architectural problems as a front-end developer. Instead of web components for instance, I would have preferred a DOM diff API as a standard which would have been far more useful that web components, all things considered.


Someone already pointed to Rich Harris' article on dev.to, but there are other things:

- form participation without javascript hacks (they are called "an API", but it's a hack) https://web.dev/more-capable-form-controls/

- SSR

- splitting SVGs into components https://twitter.com/Rich_Harris/status/1354165883648827401?s...

- not breaking accessibility by default https://twitter.com/sarahmei/status/1198069119897047041?s=20

and a million other things, big and small


What does WebComponents offer that also React offers, other than some form of components?


a coherent strategy for keeping state and having the UI respond to changes in state


That works well... until you have stateful components and you want to send in new props. At that point the recommended approach is to replace the entire component by using the key property.

For simple components, especially stateless ones, React works well. When the component needs to manage user interactions it needs state, and then if you need to update props you have to make a new instance of the component, and that point React has failed in its promise.


> At that point the recommended approach is to replace the entire component by using the key property.

Where did you hear that? React.Component has both props and state and both seem to work pretty well together, and you definitely don't need to destroy the component by changing the key property just because props changed.



> When the component needs to manage user interactions it needs state, and then if you need to update props you have to make a new instance of the component

That would suck and make React completely unusable, but it isn't true at all. Assuming that there are necessary state/prop interactions to track (sometimes the two arr largely orthogonal, so you don't need this) you might need to add additional state variables to do last value tracking for props, and then do (with useEffect hooks in a function component, for instance) state updates based on prop changes as needed, but you don't need a new instance on prop changes, generally.



You made a “you have to do X” claim, and then point to a documentation page that shows you don’t have to, even though it is the recommended pattern.

React works fine with components that don't follow the recommendation, though if you freely mix internal state updates and external updates via props that shouldn't represent instance changes, you can very easily make something unnecessarily difficult to reason about. So the recommended pattern of either doing a fully-controlled or fully-uncontrolled component is a sensible recommendation that makes sense to guide design. But nothing will break and the React cops won't arrest you if you use props driving state, though if you do too much of that whoever had to maintain your code may be upset.


I am assuming you're debating in good faith (and not just trying to win an argument). The recommendation made in the docs is very well justified. All other techniques are a mess, and lead to maintenance problems and bugs. Just replace the component by changing the key... you can thank me later.


I'm not sure what you mean, could you clarify? Having a stateful component render something different based on a prop change is core to react. Using the key property "resets" the component by rendering a new one, but just because you use state doesn't mean you can't change props.



What do you expect to happen? You ultimately have to store the state somewhere. Either it lives in the component, or outside of it, or you figure out some strategy to combine the two.


Once you realize React doesn't work for complex components it loses its attraction. Web Components are conceptually way simpler and work well. See example:

https://github.com/wisercoder/uibuilder/blob/master/WebCompo...


Simpler? I don't see it. That looks way more verbose than a React equivalent component I would write.


I don't really see anything here that would be massively more complex in React. And besides, I've been hurt enough times by manual DOM manipulation to never want to do it again for interactive UI. It's a maintainability nightmare.


does web components have a usable templating language? last time I checked there was some kind of mysterious slot update thing that made interface code 2-3x bigger


> usable templating language

ES6 multiline strings? Enhanced for convenience with a library like lit-html?


Rich component libraries like antd and material.

https://ant.design/components/overview/

https://material-ui.com


employment opportunities




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: