* If there’s only useState, then everything is mostly fine. All is good.
* To avoid unnecessary re-rendering you’ll have to move callbacks into useCallback. These callbacks then also need to specify all of their dependencies. So many lines of code that are merely noise.
* They encourage having state locally in the component which often breaks down the moment you slightly tweak the design. So much refactoring!
* Dealing with any other (callback-based, stateful) API is confusing. If you want something to execute once initially you can use useEffect with an empty dependency list, but note that then there’s no way of accessing updates values (in callbacks) and everything will reflect the initial state. Often you’ll have to use useRef just to keep track of the current state. Or maybe useState?
* Debugging is painful. You forget one value in your dependency list and the weirdest things happen. Suddenly you have callbacks running in different rendering scopes with different values.
They feel very “brittle”: Once it works the code looks pretty, but when there’s a slight change of requirements you need to rethink everything.