> Hooks didn't come out of left field and the growing number of HOCs and how hard they were to build/maintain/debug was a part of the impetus for "inverting the dependency injection" and building hooks.
I agree. However, while hooks solved one problem that you illustrated, it created another one: more and more business logic is tied directly to component lifecycles.
Further, in order to write tests we have one good tool: integration testing by setting up a mock API. I'm not saying that's necessarily bad but it's quite a huge lift as compared to passing props into a component and seeing what happens.
Yes, I think that's an inherent balance problem, and a criticism of hooks that I agree with: hooks make it easier to slice in other concerns so more concerns are sliced in that maybe shouldn't be. HOCs were hard and a pain, which kept them relatively infrequent. As a better replacement, hooks are sometimes in a weird spot of "making it too easy".
As other commenters point out the lament that Redux has mostly fallen out of fashion, where my own experience points out that Redux is still incredibly useful post-Hooks. (For testability, for separating concerns in clear ways in a codebase, and even for debug-time tooling.) Hooks are good at what they do, but what they do should probably not be your entire business logic of your app. Striking that balance is hard, different teams have different ideas and ideals. It may take a bit before "the best pattern" emerges from all this.
Sometimes I wish post-hooks that there was a good way again to spot "pure" components in the wild (entirely prop-driven with no internal state). Obviously, pre-hooks this was sometimes very easy to see in a codebase "pure" components were most often written as functions because functions had to be "pure" and stateful functions had to be written as component classes. Maybe less obviously that wasn't always a clean distinction either: there were plenty of pure components written class-style simply for habit, and there have always been ways in JS to sneak side effects into even "pure" functions, but it was a good enough first-order approximation that a lot of people relied on it, including myself. I don't know if there is a good way to mark "pure" React components today in a similar first-order approximation other than in documentation, though documentation is a good place to start and most libraries aren't currently doing even that and about the only reliable test is to grep /[\b]use/ through your project, and even that has some issues with not every hook follows the "useSomething" naming pattern, just most of them. (And the false positives that "useSomething" may still be the best name for even a non-hook function.) I don't have a good answer here, but I do understand it as a pain point of hook usage, and one that is a low level bother to myself too.
I agree. However, while hooks solved one problem that you illustrated, it created another one: more and more business logic is tied directly to component lifecycles.
Further, in order to write tests we have one good tool: integration testing by setting up a mock API. I'm not saying that's necessarily bad but it's quite a huge lift as compared to passing props into a component and seeing what happens.