I’d say the two biggest hazards with the reactive/declarative style are cyclic dependencies in the data model and remembering history.
Tools like MobX let you write quite elegant code in the right circumstances but they are less helpful if, for example, you have a complicated set of constraints and the effects of changing one value in your state can propagate in different directions depending on what first changed to start the cascade.
This style also tends to emphasise observing the current state of the system, so if you need a history as well (for undo, syncing with other user actions via a server, etc.) then you probably have to write a whole extra layer on top, which is more work with this kind of architecture than for example if you are using a persistent data structure and reducer-style updates (as popularised by Redux within the React ecosystem).
For a project that was basically an after effect like application I needed a history, but also very fast updates, settled with mobx-state-tree which gave me a way to preserve history. Worked great for that application, no regrets.
So there are some solutions available if normal mobx is not enough.
This is a really great explanation - I love MobX in many ways but the “observing the current state of the system” definitely has its downsides, which you’ve expressed very clearly!
What problem does MobX not already solve?