useEffect makes easy things easy and hard things very hard indeed.
After building a few non trivial apps in React with hooks I'm convinced that what you really need for that model to work smoothly is a new language that tracks things like hook dependencies for you.
The ESLint plugin helps. But it depends on static analysis. And static analysis is fundamentally incapable of taking advantage of any information only available (or more easily accessible) at runtime.
One limitation that pops up fairly frequently in my experience: Only React's first party hooks can get exceptional treatment by the plugin, i.e. the setState function returned from useState can be assumed to never change and omitted from dependency lists, because those cases are hard coded into the static analysis. There's no way for custom/third-party hooks to indicate to the plugin that the thing they return will never change in the same manner, even if all they're doing is passing through a setState function directly from a useState call that will very obviously also never change reference, for instance.
They can probably offer some rudimentary support for this use case with static analysis by offering some kind of exceptions API for the user to spell out the names of the hooks and return values that should get this preferential treatment, like they have with the additionalHooks config option [1], but the DX around integration with third party modules is going to remain a messy unsolved problem.
Language/runtime level support for this pattern would hopefully be flexible enough to know that the thing we returned from our custom hook or third-party hook is fundamentally the same thing as (or shares some runtime property with) the setState returned from a useState hook, and treat it the same way, regardless of what our hook is called or how it's implemented or where it's from.
Unfortunately it sounds like the React team is planning to double down on static analysis to improve hook DX, so this doesn't seem to be an area they'd be likely to invest in. I think that's a shame because static analysis is much more difficult for users to extend and experiment with new paradigms for than runtime abstractions, and will start to stifle innovation in the ecosystem as we come to rely on it for more and more heavy lifting.
[1] Which, by the way, stops working as soon as you deviate even a tiny bit from the assumptions made in the static analysis, in ways that would be completely trivial to infer as functionally identical for any runtime system. The only way to address these shortcomings is to send in a PR to make the static analysis make fewer assumptions (unlike a runtime system which you can usually extend through some clever wrapping if it's just a function), for which YMMV: https://github.com/facebook/react/pull/20051
I agree with all of this except your terminology: static analysis of javascript can't solve this problem because of the limitations of the language semantics. Static analysis in general could, I think. It just might require a different language with different semantics.
After building a few non trivial apps in React with hooks I'm convinced that what you really need for that model to work smoothly is a new language that tracks things like hook dependencies for you.