To make complex layouts (flex, ...) and have them run performantly you need some form of a retained backing state anyways.
The main difference between various retained, OOP, functional, immediate, declarative, ..., approaches is how they treat this state.
For imperative/retained/OOP libraries, you operate on this state itself. Your nodes/widgets know their own state, how to render themselves, their place in the hierarchy and so on.
For immediate/functional(?) libraries, this state is a cache. It's not something you work with directly.
Despite not really liking React itself, I think it has found the best model.
You take a retained core, possibly OOP, maybe ECS or whatever, and you write a declarative wrapper around it. This lets you escape the easy-mode declarative landscape when needed, but most UI can still be simple to write.