Calling classes messy isn’t really a strong argument. classes are one of the valuable tools in a programmers toolbox. Emulating them via a bunch of closures that act on shared state isn’t necessarily better.
Not only that, but classes are at odds with advanced render scheduling like React is moving towards (concurrency, prioritized rendering, context switching, bailing out of renders, etc.).
With a class instance, what happens if you need to bail out of a render and potentially restart it again later? The developer could have done literally anything to their class instance the first time through. They could be inheriting from anything and doing whatever they want to `this`. You can't easily "restart" it from its original state, unless you made a perfect snapshot, which is not easy with class instances – you'd need to perfectly deep clone the prototype chain and such.
With functions and hooks on the other hand, there is no class instance or prototype chain to worry about. All state (whether stored via useRef or useState) is controlled by React – the actual object it gets stored on is hidden from the developer. If React wants to ditch the "instance" it was updating on the previous attempt and reuse the one it started with, it can do that without worry.
It's the same reason "time travel" features are easier with more functional approaches. Adhering to functional programming ideas pays off in the long run.