Hooks are much worse because they
poorly emulate classes.
What you need for components is a stateful container, with an initialization phase, a render function that can be called for each update, and lifecycle methods that are called at lifecycle events.
Classes give you exactly this:
- Constructor for initialization
- Class fields for state
- A method for rendering that can be called multiple times, which can reference state
- Lifecycle methods
Classes are simple, standard, and give you everything you need for UI components. They were practically invented alongside the concept of UI components.
Hooks try to cram all of this into the repeatedly called render method and it's just a failure.
- You have to put initialization into callbacks because the whole component is called multiple times
- It's difficult to manage object and callback identity across renders requiring useCallback() and useState() to fix
- Lifecycle callbacks are put into hook arguments, but they're just trying to be methods and end up recreating the lifecycle closure every render.
- Hooks have restrictive rules on their usage
- Hooks make a function no longer just a function. It needs to be invoked inside a hook context, making it much less portable than a constructor
- Hooks hide their state within the hooks system, making them much harder to introspect and debug.
Hooks supposedly solve this composition problem and allow reusing logic, but that is entirely possible with classes. It's just a huge amount of FUD and misinformation to say that you can't do composition with objects. All you need is an object interface that is similar to the component interface that the component delegates to from its lifecycle methods. This is a simple and standard pattern to use and implement: it's just a single line of code per lifecycle method. And it's easily introspectable with a debugger: just follow object references to the helper objects.
lit.dev does with with reactive controllers: https://lit.dev/docs/composition/controllers/
It's a very simple alternative to custom hooks, and eliminates the need for all the builtin hooks.