The main issue is that these terms are extremely overloaded in compsci. I think they must have at least 3 or 4 completely distinct meanings in common use. I have gone back and forth several times on terminology. My current preference is to always use the phrasing “declarative style” as you may have noticed.
The best explanation of this, and the one that finally made it click for me, is that of this article. The definition of declarative used there is something to the effect of “writing code which rebuilds itself from scratch each time”, as opposed to “writing code that mutates state in pieces” (the author calls this “delta code”). But definitely read the article because I cannot due such a complex topic justice in one sentence.
This was an important realization for me as I had previously thought of declarative as being a property of a language or runtime as opposed to the structure of the code. And in reality both are probably valid definitions (because the term is so overloaded). That’s why I’ve been going with “declarative style”.
Quite the opposite. React-like engines are useful as tools for making code written in the declarative style more efficient. What React is, actually, is an unstructured incremental engine. It’s a tool for writing flexible incremental code. Incrementalism is the key to making declarative code efficient, as otherwise you have to rebuild the universe from scratch on every invocation of anything.
Unfortunately pretty much nobody criticizing React seems to understand this. Most people advocating for React don’t seem to understand this either, nor unfortunately do most people using React. I’m not throwing shade btw, it’s not like I understood this either until relatively recently lol. Live and learn.
Which is why that “definition” of declarative isn’t really very useful for anything.
Taking the meaning I gave above, the reason JS.show() is imperative and bad is because you have to call it each time you want to show/hide something. Whether something is shown/hidden should be downstream of the state which is re-computed in full on each render.
When you write imperative code (“delta code”) you have to duct-tape all of your codepaths together to keep things working. User clicked show? Show! User clicked nav? Hide! Notification appeared after user clicked nav after user clicked show? Uh, idk? And so you get bugs. Endless bugs.
The problem with this, as detailed much more beautifully in that article, is that you are forced to write O(n^2) lines of code for n pieces of functionality, which fundamentally limits your ability to design complex behavior. This is why many apps in modern times are so limited in their functionality. The authors do not know how to manage the complexity.