Keeping a program's state consistent is a challenging task. Once you throw exceptions and error handling into the mix it gets even harder. If you add the ability to observe values & objects as they change... well it becomes nigh impossible.
As such, mutable state is rightly frowned upon and a trend towards functional programming and systems like Redux have gained steam. Their key insight is that you make all your changes in a new copy of state and, once that is done, replace the old copy of state.
Trying to manage a giant tree of completely immutable state can be rather complicated, however. Especially when you need to update deeply nested state in that tree. It gets harder again when you need to compute what parts of the tree changed in order to notify interested parties.
So lets take a lesson from relational databases. Relational databases provide a set of global and mutable state yet we have very few problems with the state managed by our databases in comparison to state in program memory. This is because the database provides better abstractions for handling mutations. Namely transactions, atomic commits of transactions, transaction isolation and rollback on failure.