> React Hooks were fanatically adopted, in my opinion
It was one of those things where the ecosystem had to be unified, because a fractured ecosystem would have died. The React team said "this is the way we're going", and people followed along not because they were fanatical, but because that's the path that was set out. We can debate whether hooks were the right call for the core team to make, but I think it's incredibly uncharitable to say every library author who went along with it was just being "fanatical"
> I find it, thusly, infantilizing to hide those details
Software development is all about hiding details. The key is picking the right details to hide and not hide. Hiding details (ideally) lets users focus on the parts that matter to them, and gives the compiler/framework/system room to optimize the rest.
In React's case, we got features like automatic batching (https://react.dev/blog/2022/03/29/react-v18#new-feature-auto...) and concurrent mode (https://react.dev/blog/2022/03/29/react-v18#what-is-concurre...) for free, without having to modify application code, because the application code was already abstracted enough that the framework could significantly change how it did things behind the scenes without changing the contract
In terms of developer experience: I consider myself to have a fairly deep understanding of the browser platform, and a fairly-complete understanding of how hooks "really" work, and I'm still glad that I have React's abstraction layer most of the time when doing real work at my job. There are escape-hatches, as there should be, and the rest of the time I'm really very happy not to have to fiddle with all the bits when I just want to render another form and implement some business logic. I don't feel the least bit infantilized.
There are things I don't love about hooks - mainly that they do things which should really be language-level features, and that causes some dissonance - but here's what I love about them:
They expose a tiny set of primitives - pretty much just useState and useEffect (useMemo, useCallback, and useRef can be implemented in terms of these!) - which plug directly into the simplest, smallest side-effect-y things we need to be able to ask the React framework to do for us. And then, because these state and side-effects primitives have their own reactivity baked in, we can compose them into larger stateful/side-effect-y abstractions which also have their own reactivity baked-in (unlike classes, unless those classes are full React components). We can build amazingly high-level, convenient abstractions on top of this amazingly minimal set of reactive primitives, which will always themselves be reactive, no matter what. And then the framework can break them back down into the primitives at runtime (in fact, it never sees anything but the primitives), and schedule and re-order and do all kinds of nifty stuff with them without breaking contract, because the contract is tiny and elegant.
In my experience that's unique and beautiful.