IMO if you need a long doc like this pointing out the sharp edges, then I think you've done a poor job in designing the framework.
I love the terseness, reusability, and typing of React hooks, but hooks have too many weird edge cases (this article, dependency list, order of hooks, etc) versus class components, whose design was simple and elegant.
I'm just an old man yelling at clouds though, the terseness of stateful components defined in a function, plus simple typing with TS (no defining proptypes) is too appealing to me personally. Maybe I'll check out Solid next time, which seems to have less weird edge cases.
I actually disagree here pretty heavily and think that this doc is due to the bar for competent developers going down in recent years (due to the rise in necessity for more developers of course). There's almost an expectation that powerful tooling should be dumbed down.
The entire doc is written around two common problems:
* You don’t need Effects to transform data for rendering
* You don’t need Effects to handle user events
Both of these problems do not occur if you take the time to understand the tooling React gives you. The events point should be a given, that's just React 101 (and yet they have to spell it out to people...).
You don't end up using useEffect to transform props/state and generate new state if you understand that those things are just variables and you can instantiate new variables using them inside the scope of the component function.
"But that's inefficient because of how re-rendering works".
Great, you understand how re-rendering works but haven't gotten familiar with the useMemo hook. Come back when you've gotten familiar with the primitives available to you in React and how they can all work together in different ways, there's not that many of them!
This doc reads to me like a DIY store publishing an article about how you shouldn't hammer in screws even if it kinda seems like you could if you didn't take the time to understand hammers, screws, and nails. It's sad that it needs to exist but that's the current state of engineering.
Your entire argument here is a shining example of how the growing complexity of react has raised the bar of skill for competence rather than being a victim of lowering the bar.
Think back to the webdev world before react. Was it really that the average dev was more competent, or that the tools of the day were in fact more simple to use? Sure there are more and less efficient ways to use jquery, but unlike react you didn't have to keep so much in your head at once while building a simple feature.
React was designed to be a UI component library. We keeping asking more of it and stuffing more and more complexity into react so that monolithic frameworks can be built with it. It was never designed with that goal in mind and is taking more and more complex features to try to keep that ship afloat.
I really like React. I don't know if this particular pattern was explored before, at least I didn't see it, and I used plenty of UI libraries, from WinAPI, MFC to Java Swing and plenty of web frameworks.
I think that JSX support is a genius thing. Especially with modern TypeScript. I spent so many hours because of string-typed templates that I really value templates integrated within a language.
I really liked original React version with classes. It had its rough edges, but it was simple and accessible to me.
Modern React with functions is not simple. It's so far from simple. I consider myself pretty talented developer. But those hooks - I think last time I had to spend that amount of time is when I learned Scheme continuations. That thing really broke my mind. Well, hooks didn't break my mind, but they just seems to be very easy on the surface yet very hard below surface. I read plenty of articles yet I still don't fully understand them (although I think that at least I can use them without bugs).
For me React is like ORM. It's very powerful tool. I allows to tremendously cut the development time. But it requires absolutely expert knowledge on the team. And it looks so deceptively simple at the same time. This is a bad place for technology to be in.
I first tried react rigtt as it was shifting from class-based to functional components. I actually really liked the functional approach at first, but to me the promise was just pass in props and spit out html. No async components, no hooks, no data fetching, at best it just needs a way to attach even listeners once that fire custom events.
With all business logic outside the render tree it makes a ton of sense and really can be understood extremely fast. Props in, events out. Done. Today everything is a component, and components even have to understand whether they are in the server or browser and how to manage that handoff. It's such a massive dumpster fire of convention-as-a-solution.
Having built a SPA without React it was 100x harder to do it. You had to be careful to update so much state that there was no way really to not break far away stuff when making small local changes. It was a maintenance nightmare.
Yup. And jQuery, awesome as it was, wasn't designed to address the state issue. But it was the best DOM abstraction, so that was the backbone (no pun intended) for many pre-framework applications. It was a spaghetti nightmare.
> We keeping asking more of it and stuffing more and more complexity into react so that monolithic frameworks can be built with it. It was never designed with that goal in mind and is taking more and more complex features to try to keep that ship afloat.
The trouble with a smash-hit library (or, let's be real at this point: framework) is that adding more whizz-bang features to it becomes irresistible, from a résumé-building perspective. Add in that a bunch of the devs are paid very good money to work on it, and they really do have a lot of incentives to keep finding more shit to add to it, rather than calling it "done" and letting it enter maintenance mode.
> It's sad that it needs to exist but that's the current state of engineering.
Wait, wait. I'm trying to make friends with React for less than a month and I do appreciate this article giving me some understanding about the primitives react gives me and when to use it (Or how you called it screws/nails)
I did understand more, but I'm left with a feeling I cannot follow the "flow" of the useEffect as I couldn't understand how can items !== prevItems EVER be true?
// Better: Adjust the state while rendering
const [prevItems, setPrevItems] = useState(items);
if (items !== prevItems) {
setPrevItems(items);
setSelection(null);
}
useState doesn't return immediatelly? Or does it cause immediate re-render? I kind of gathered from the article that all useState calls cause re-render whenever it encounters return.
I am not sure I understand your confusion but here's a few pointers in no particular order:
- the argument passed to useState is initial state, not "forever state". It will seed prevItems for the first render. But later when items prop changes, it's on you to detect the change to what you have as prevItems so far and call setPrevItems yourself.
- items is coming as a prop from outside, prevItems is whatever you set it to last time using setPrevItems
- calling a state setter (setPrevItems / setSelection etc) will always cause a rerender. That's why if you don't have the if condition you have just created an infinite loop - you are inside a render, and if you unconditionally call setX that causes another rerender later etc etc
- that's why I am not a big fan of this particular "Better" example and prefer the later "Best". Avoiding calling state setter function from inside render will make your life easier.
Well, in the first place, this code snippet has nothing to do with useEffect, so I'm not sure why you're bringing it up. They have a separate page that they linked to that explains this pattern in more detail: https://react.dev/reference/react/useState#storing-informati...
But to summarize that page briefly, useState will always return the current value of the state and a function to set it. But "items" here is being used as the default value that's provided the very first time the component is rendered, when the state doesn't exist yet. In subsequent renders, the state exists, so "prevItems" will reflect the last value that was set with `setPrevItem`, not the current value of `items`
yeah I agree with a most of this, but useEffect is still a shit show. It's nasty, and it sits in your code like an anvil, heavy and terse, it even looks like one, with it's lopsided dependency array. The semantics are so strange, and it's not even really for side-effects, more so for synchronizing state. And while I love React, it's not uncommon to see entire codebases where every function is wrapped in useCallback and useMemo, you know, "just in case".
I had a horrible time trying to convince junior devs that they didn't need to memoize everything. Ended up just quitting rather than work with that shit show of a codebase.
Overuse of useEffect is my number one pet peeve for juniors. I can't tell you how many times I have seen a total mess of manual data passing between 3 components with so many if..else cases to handle all the weird stuff.
I catch it in code review and show them that when you delete all of it without useEffects and useStates that it just works. Its an antipattern that turns the code into a giant ticking time bomb if you don't manage all of it out.
> I actually disagree here pretty heavily and think that this doc is due to the bar for competent developers going down in recent years (due to the rise in necessity for more developers of course).
> There's almost an expectation that powerful tooling should be dumbed down.
Which is the problem here. The abstraction in question tries to dumb things down, but doesn't succeed in dumbing things down enough. As a consequence you get their weird middle ground where you can't access the gritty details an experienced programmer would want, but it doesn't hide the gritty details from the inexperienced programmer, ultimately serving no one. As usual, you can make it work, but it is a poor abstraction.
useEffect and dependencies are the worst part of React at the moment.
The reason is, you do need to use effects, everywhere in your code, constantly. And dependencies, and the linter rule that goes with them, are nasty ergonomics, and hard to reason about.
The article I linked does explain it all quite well, and most devs I work with do understand the dependencies rules, but the rule still needs to be disabled often. Why?
Often the lint errors really are just wrong. Just like ChatGPT is often simply just wrong, no ifs or buts. For example: you have a callback function declared as an expression, that the useEffect hook calls. The linter will say "oh this is an expression, therefore it needs to be declared as a dependency". But it doesn't, because looking at the code as a human, you can immediately see the function never changes.
If you follow the linter, you will inevitably end up going down a destructive and unnecessary refactoring. You'll end up with unnecessary `useCallbacks` sprinkled everywhere that hurt readability for nothing. Often, you'll have to refactor the dependencies out of the component entirely, splitting one cohesive component into two, just to satisfy the linter out of an abundance of caution.
Junior devs will be confused. Senior devs will be frustrated. Every react codebase I've worked on has gagged this linter warning.
So how should this work?
It shouldn't be a a linter error in the first place. Linters should be used to enforce coding standards, not fix application bugs. I feel very strongly on this.
"For example: you have a callback function declared as an expression, that the useEffect hook calls. The linter will say "oh this is an expression, therefore it needs to be declared as a dependency". But it doesn't, because looking at the code as a human, you can immediately see the function never changes."
Can you elaborate on this? In my experience this isn't the case. If a function is declared outside of the component scope then it won't trigger a lint error. If it's defined within the component scope and not wrapped in useCallback then it does in fact change on every render and the lint error is being raised for good reason.
> If it's defined within the component scope and not wrapped in useCallback then it does in fact change on every render and the lint error is being raised for good reason.
So I just did some playing around to investigate this further, and it seems to be more subtle than I thought.
If you have a function expression but the expression is not dependent on any outer scoped variables, the linter does not complain that you didn't specify the function itself as a dependency in useEffect. Example:
```
let bar = "bar";
const setResult = (result: string) => {
// Won't trigger "exhaustive-deps"
setBio(result);
// Will trigger "exhaustive-deps"
if (bar === "1") setBio(result);
};
useEffect(() => {
setResult("");
}, [person]);
```
So there's some quite sophisticated analysis of the AST going on in the lint rule.
I still think that this rule is too complicated for a linter. (Bugs like inter-dependencies in your data and code should be caught by unit tests).
But it's technically pretty impressive.
Edit: I did some more investigations.
If I make a function that depends on something very unpure (like checking window.___location), the linter fires if the unpure function is in the outer scope of the hook, but not if it isn't. Even though the dependency is the same. So the linter rule can only identify locally scoped dependencies I think.
I recommend you read the article again. Just because window.___location changes outside scope doesn't mean that React would update the component when window.___location changes just because you put it in a dependency array.
This is because props or state didn't change and the parent didn't rerender.
UseEffect dependencies aren't observables. You'd need to wire up an event listener on unload, hashChange, etc
> Bugs like inter-dependencies in your data and code should be caught by unit tests
Why write a ton of unit tests for what a static check can just do “for free?”. Not sure i follow your logic. I agree React can feel like a nuisance, but the lint rule itself is not the issue i think you have, it sounds like your issue is just with hooks.
Its not necessarily that the function depends on something 'very unpure', its if it depends on anything which is non-primitive that is created or assigned within the component fn body.
window.___location returns a Location object which is not a primitive, and so it will trigger exhaustive deps if it is being used by way of a reference inside the component render function (assigned to a variable), since it could theoretically be a different object reference on subsequent renders.
Since the linter can't necessarily tell if the reference has changed out from under it on subsequent renders due to the fact that it could be mutably changed, it marks it as a necessary dep.
There is a new experimental hook, useEffectEvent, whose only discernable functionality based on the documentation and information available is to quiet the linter. I'm not sure that's all it does since I haven't dug into the React source code, but that's what many are speculating.
It makes it so that the same instance of a function is used for all renders, but that it always points to the data closed over by the latest render; it eliminates a whole class of scenarios that normally lead to gnarly dependency array tomfoolery with useCallback, useMemo and useEffect.
It's quite a common hook to try to invent in user-land (i've seen it in numerous projects), it's not just a linter silencer.
> but that it always points to the data closed over by the latest render
It's my understanding that this was to be the behavior of the canceled useEvent hooks but that the new useEffectEvent hook does not return a stable reference.
Do you have sources for the behavior of the new hook?
> Here, onConnected is called an Effect Event. It’s a part of your Effect logic, but it behaves a lot more like an event handler. The logic inside it is not reactive, and it always “sees” the latest values of your props and state.
A bare closure would always see the latest values because it closes over them during render. And the latest useEffect closure will have closed over that method..
You're right, i'll redact/edit. Hm, this doc page is exceptionally confusing.
Edit:
So it's kind of interesting, this test (and the functionality behind it) exists specifically to make sure you can't rely on it having a stable identity -- and therefore have to omit it from the dependency array. But it otherwise behaves the same as the popular user-land implementation involving refs (which you still have to include in the dependency array, because it works by providing a stable identity).
So there's some internal trickery in React to make sure that even though the effect event is recreated and has a new identity on every render, any time it's invoked you're accessing the latest inner callback.
As far as I can tell, useEffectEvent is just the useEvent hook but renamed to reduce scope. useEvent was originally going to provide performance optimizations when creating event handlers in a function component and it was going to solve the issue of event handlers causing effects to re-fire[1].
The funny thing is that React already kind of has its own programming language: JSX. If they wanted to, they could add language features to support React. I expect that would be very controversial though.
Svelte is pretty pleasant, compared to React. It's fundamentally a JS-to-JS compiler that adds reactive assignments, and ridiculously much more usable than useEffectHopeThisWasTheRightThing.
let count = 1;
// this is reactive
$: doubled = count * 2;
function handleClick() {
count += 1;
}
Reading sentences such as 'Effects are an escape hatch from the React paradigm.' in the official documentation in 2023 while writing React since 2015 makes one depressed and angry (deprangry?): then how are you supposed to use this 'library'. Luckily they provide a firstName/lastName example, because that's all we use React for, no?, login forms and hello world todos apps.
As with everything, if you want to make an apple pie, make a universe: after all, the mistake was mine, starting to use React in 2015 instead of making my own language/framework, mainly because what I have today is already a bunch of highly idiosyncratic React utilities. If there is one hope with the large language models hype is to finally be able to code against a true common interface (the HTML/CSS/JS specification), and do it anyway you please, translating on the fly any third-party dependency.
Part of the problem is that React was never a "framework" to begin with, but people treat it as if it is. React began its life as a view library for creating custom components. That initial design decision has permeated every attempt to make it more "framework-like."
In a traditional MVC-like paradigm, components would just be views. Discussions would be focused around keeping your components limited to view concerns while using other, non-view parts of the framework to drive things like API integration, business logic, state management, routing config and so on. Which is to say that you wouldn't have a need for "effects" at the component level in the first place since, by the time your data is ready for presentation and your components are initialized, all of that has already been done separately.
So yes, it is a design flaw with the "framework". One that came about by trying to morph what was, initially, a simple view library into something more "framework-like."
IMO the simple old class & props was all that was needed. Lifecycle was much easier to understand, most reusability issues could be solved one way or another.
Most bugs I find in big react projects are either by using multiple useEffects in one component, and the other one with Saga. Also another "side effect" tool.
Class component usage patterns where "lifecycle was much easier to understand" were inherently problematic though; they led to redundancy and verbosity, grouping unrelated code in a given lifecycle method and fragmenting otherwise-related code across disparate methods. Those deprecated lifecycle methods are overly imperative, with poor ergonomics. (Dan Abramov wrote a great post about these shortcomings; I'm on my phone or I'd try harder to dig up the bookmark).
Don't get me wrong, I have fond memories of using classes as bags of methods (esp with Mobx) and it took me a while to come around on hooks. But given your "most bugs... useEffect... and Saga" (does anyone still use Saga?), maybe the over/misuse of useEffect -- not hooks / FC more generally -- is the crux of the problems you've encountered. Which might even reinforce the OP (shrug). :)
Those are tradeoffs. Lifecycle methods had pros and cons. Hooks have other pros and cons. Lifecycle methods had the right pros and cons for most devs. Hooks are horrible for new devs, as they have to many gotchas, and there far too many people that just don't have the time to learn all the footguns of hooks.
So lifecycle methods had some other drawback? Yes, sure, but they were less than the drawbacks of hooks for most people.
We're agreed that nearly everything has pros and cons.
But these confident assertions about what's "right" or "horrible" are subjective, personal preferences.
And unsubstantiated claims that they apply to "most devs" or "most people" is merely a projection. That contradicts my direct experience (I've never encountered a single team that adopted hooks and went back). Hooks' adoption rate (along w React's market share) suggest I'm not an outlier.
All that said, I'm glad TMTOWTDI. I also want to pause and thank you for sharing your perspective; dissent is valuable and helps prevent groupthink.
It's hard to leave hooks when you are using React, as they are everywhere. What people do instead is use something else next time they start a project.
This will happen fast. I'm not even using Solid - I like the html first approach of Svelte - but the writing is on the wall. The data is saying as much.
I was using Angular in 2013 when React came around. I knew Angular was dead as soon as I saw React. Took the Angular people many years to realize this, and many still haven't. I'm saying React is already dead. Svelte and Solid killed it. It will take a few years to play out, but you can see it happening already if you pay attention. The React devs are doubling down on the inherit complexity of React instead of cleaning it up - this is exactly what killed Angular and made people move on to something simpler.
I am extremely confident that this comment will age well, but we'll see :D
The steep curve of Remix is really beautiful. One possible way of interpreting it is that it is coasting of React, and isn't starting from as low a starting point as Svelte and Solid have to. Just the mere fact that Solid is showing a hockey stick curve, and that it is so different from React is what has me convinced.
Sure; Svelte and Solid look promising. And for those of us who like TSX and the better parts of React, Remix's embrace of web fundamentals and its relative simplicity are a breath of fresh air. It's powerful and intuitive, with a really well-designed set of features that represent a coherent paradigm. The return to web fundamentals -- eg its approach to forms -- resonates deeply with me and my peers (building websites and apps for a living since 1998).
A rising tide lifts all boats, and I'm glad there are choices.
It was pretty easy to group unrelated code into a seperate function either in the class or in a seperate module. Every beginner programmer can do that. To write a hook is much more complicated.
Dan is very smart, also redux was very smart but ended being an overkill. Side effects are a concept only thought at the Uni.
That's the core of the issue, useEffect is too complicated. As well as Saga. Even for simple requests it can become tricky to figure out what the flow is.
I've run into race conditions inside of react that has made me gobsmacked. I swear the thing must be written by fresh faced middle schoolers.
I'm so glad I don't have to deal with it anymore. After being in programming for over 20 years, I started making plans to exit the entire industry. Now I realize it was just react. That thing made me despise programming. I kept a virulent twitter journal of my time in react. It seems foreign to me now. Good! Example(s): https://twitter.com/SisNode/status/1458942812087414797 ... it made me pretty intolerant https://mobile.twitter.com/SisNode/status/143380932394827366...
The tweets in that account are like an insult comic does programming.
From this account, you seem very unpleasant to work with. Anger just makes you more angry and bitter, you gain nothing by being this angry, and people who see your comments are hurt by them.
You said you keep it private and try to be well behaved, but it probably comes out in your interactions with others, whether you're aware of it or not.
hey thanks. I know there's always many actual people behind all these projects trying their hardest. I hope nobody takes my jeers personally. I'm playing a character.
I mean sure, the passions are real but I'm also ostensibly a well behaved sincere adult. I don't actually want to "literally stab the people who wrote [apache modrewrite] repeatedly in the eyeballs" - although a reconsideration of how transparent the flow is would be greatly appreciated.
Perhaps I should add that to my list of "things to do" and you know, fix it myself. Be responsible or something. I've become intentionally unemployed in order to spend some time on stuff like this and regroup. I should do it.
Honestly, I'm probably still recovering from that react project. Maybe I should do some therapy. It was bad.
> IMO if you need a long doc like this pointing out the sharp edges, then I think you've done a poor job in designing the framework
And it seems that the React maintainers don't understand their own system, in a sense.
That obviously sounds a bit weird, but as far as I can tell they seem to think that what makes React good is that it is "functional". And so when something isn't quite right, they "fix" it by making things more functional. And that seems to invariably make things worse. Rinse and repeat.
Hmmm...
What if the good part of React is that it is a reasonably decent UI widget framework for the web? And that the FP-ish nature is really more an implementation detail due to the way it is embedded into the web platform? And that this led to the happy accident of being able to write the UI as a procedure that structurally reflects the UI to be displayed?
Really it is quite an amazing situation. The conceptually clunky but easy to understand class components vs the conceptually pure but esoteric hooks. Even at the time the React dev team were putting in a lot of effort to say "you will get it soon, don't worry", because they already knew it was in many cases difficult to understand and use properly. That should have already been enough of a sign to not push it so hard.
Be warned that the state of docs is very weak, and that although the Solid team acknowledges this issue and are working on a beta¹ version of the docs, the effort really crawls along. It's also really hard to get help. Maybe there are many Solid lovers, but there aren't enough Solid intermediates to help prune the support forum. I attribute this to slow progress of the docs.
[1]: Note that this docs effort doesn't include SolidStart, which is a big bummer.
> I love the terseness, reusability, and typing of React hooks, but hooks have too many weird edge cases (this article, dependency list, order of hooks, etc) versus class components, whose design was simple and elegant.
You know, I kind of agree and personally prefer Vue (that does hooks better in some ways, as well as has a simple store solution called Pinia that's nice to use), but I have to say that these docs themselves are great.
Even if there is some awkwardness about using React and it needs some getting used to, to be able to use it effectively, I think these docs are definitely a step in the right direction and offer concrete examples! The code is mostly clear, the text explains everything bit by bit - we could use more of that in our industry for sure.
It's a sad state of things where React—even with hooks—is considered by some developers as "terse". It makes me wonder if we're all actually speaking the same language.
The problem is that React was designed to allow you to use functional programming to express a UI that is a function of state. It might be obvious to experienced functional programmers not to sync internal state using effects in this way, in no small part because they understand what a side effect is already.
> dependency list
This, again, is only confusing if you don't understand what an effect is for: syncing with systems external to React. How else would you say "do the thing when any of these change"?
> order of hooks
I never understood why this was confusing for people. It takes 2 seconds to learn this rule, and your browser console will yell at you if you violate it.
There is nothing in React I'd regard as "terse". Perhaps slightly more terse than the mountain of boilerplate it required previously, but that's as far as I'd go.
They exist solely because React's underlying model is insufficient and we, the developers, are being made to do the computer's job with all this optimization boilerplate. The VDOM is dying. Let it die. It's long past time to move on. Any further React development in the existing foundation is just continuing to build upon sand.
Completely agree. Class components are so beautifully simple. Hooks have infuriating edge cases and are so bizarre they need ESLint plugins to remind people how they work.
Solid has very similar API, but much simpler concept (and of course performance), it's just a plain js signal library with some ui helper functions no dark magic, whereas react is the most framework framework out there.
useEffect was designed to allow shooting yourself in the foot, in a good way. There's never a situation when react doesnt allow you to accomplish something - the page even a mentions of synchronising with jquery!
Whats the alternative you propose? Not allowing react to be used with any 3rd party libraries or access to browser apis?
>That is EXACTLY what I DONT want from my framework:
Unless you're happy about never going out of the guardrails set by your framework, there's going to come a point where, one way or another, you're going to need to interact with something outside of it. Are you going to wait for an official React-WASM way to interact with WASM (which is going to be using useEffect under the hood anyways)?
Frameworks with no escape hatches are hell. The escape hatch just needs to be bright, bold and with a warning on it that says "there can be demons behind that hatch, watch out".
Because React evolves in an ecosystem which is wide and varied. It's easy to be Elm and have no escape hatches when you make the language, the libraries, the standard library and the world. It's a bit harder when you have to interact with 30 years of crap.
Yeah, it's a right pain to deal with non-Elm things in Elm (including JSON data sources). It's possible but you will want to avoid it. However, I think I'd still take Elm over React if I didn't have to care about anyone else but myself.
I've used Surplus for years and love it. Highly underrated framework. It's hooks, but designed properly, and consistently beats out almost all other frameworks performance-wise.
It's in need of a few upgrades though, namely a few edge cases in the old JSX parser (it was written before Acorn had good JSX support) but works pretty much perfectly still today.
> It's hooks, but designed properly, and consistently beats out almost all other frameworks performance-wise.
Performance is nowadays one of my last concerns with frameworks. They're all snappy enough except for corner cases. More important is whether there are standard ways of doing things vs everyone inventing their own. Our company uses Vue which has standard lifecycle methods, standard way of scoping CSS etc, officially endordsed store etc. Makes it much easier to bring people up to date when they're joining the projects.
Function f is supposed to be declared outside of render function.
This way you must specify all the dependencies. JavaScript will bite you with undefined value, TypeScript will bite you with compilation error. The drawback is that you'd need to pass setValue functions which are typically immutable, but I don't think that's a bad thing anyway.
> "Function f is supposed to be declared outside of render function."
That's the cinch. To get the benefit of this proposed API design, the effect handler functions must be be outside of the render function so they can't capture any values other than the explicit dependencies. That's not a requirement you can enforce in JavaScript, so it would have to be a linter-level thing.
I think it would aesthetically run counter to the prevailing design of React functional components. For better and worse, it feels like the framework designers have made a substantial effort to contain a component inside a single function. With this design, you'd have the component and its effect handlers in the same parent scope even though the handlers are subordinate to the component.
I don’t see why productive frameworks must be obvious. Once you learn how to think in functional react, it’s a very productive framework that enables you to bang out applications
While I agree with your point, the example you gave feels like a straw man. Or at least, a separation of "sharp edges" and "long documentation needed".
Phrased differently:
Go: To make a something public, start the var name with uppercase.
C++: To make things public, type the word 'public'.
The Go pattern seems like more of a sharp edge than the C++ version, even though the C++ version might need more reading to learn.
Go using casing for access is quick but is awful when you just want to change the access later on. It's not like writing `pub` before the var/field is suddenly javaland, see rust.
No, but I don't think that's relevant. Rust or Java access is doesn't require much typing ceremony, and doesn't require you to rename a var to change the access.
I got up and running in Svelte in literally 5 minutes, and it blew me away. I just started building and referencing the docs along the way. But then...I ran into their reactive model, and spent an entire day trying to debug (what I thought was) a very simple problem. I can't recall the details but I remember it had something to do with the order of updates? It was super confusing. Moral of the story is that there are always trade-offs.
I love the terseness, reusability, and typing of React hooks, but hooks have too many weird edge cases (this article, dependency list, order of hooks, etc) versus class components, whose design was simple and elegant.
I'm just an old man yelling at clouds though, the terseness of stateful components defined in a function, plus simple typing with TS (no defining proptypes) is too appealing to me personally. Maybe I'll check out Solid next time, which seems to have less weird edge cases.