Yes, modifying global state is bad and relying on global state was a huge problem for early Flux implementations/spin-offs. However not everything that gets called "Flux" uses global state.
A naive implementation of Flux would use global instances of stores, the dispatcher and so on. This is generally not a big problem in client-side code as there is only one instance of the same application running at a time, but it can make it very difficult to solve server-side rendering, especially if you want to pre-load data asynchronously: because there's only one instance of the application running at a time, if something needs to happen asynchronously, another request might be served by the same application and you either respond with the wrong user's data or clobber the first user's state.
However many "Flux" libraries as well as Redux solve this with a very simple solution: instead of having one global instance, they have one instance per application and that instance can be passed down using React context. The context API serves a similar role as the dependency injection mechanism in AngularJS, except it trickles down the component tree and you only need to bind the dependencies when you actually instantiate the outer most component.
In other words while this ostensibly creates a kind of "global" state it is actually still wrapped in another top level component (or render function) which can be multiplied if necessary (e.g. to have multiple applications in parallel during server-side rendering). The "global" state is global to the application but non-global to the environment the application is running inside of.
As to whether this pseudo-global state (or application-local state) is as bad as global state in traditional applications: consider that Flux/Redux makes mutations very explicit. It's not possible to accidentally or sloppily modify shared state, you actually have to explicitly ask for it to be modified. Access to that state is also made explicit: React allows you to isolate the part of the code that knows about the internal structure of your data from the part that presents that data via props and higher order components.
It's not the same, for example, I got an variable here called a,
var a = {b: 1}
So a is a reference to {b: 1}, which is an object.
Here are two possibilities, 1. you can modify a to like {c: 2}, 2. you can modify {b:1} to {b:2} and a still pointing to that object.
And there is a difference. Modifyinga is changing reference, and modifying {b: 1} is changing value(internally it can be a reference too if it's {b: {x: 1}}, objects uses references).
This is a concept you would probably never learn in JavaScript since its scripting language nature. But if you ever learn Clojure or Haskell, you may find that values never change, but references change sometimes in order to simulate the mutable world.
So functional programming mean side effects and mutable states should be isolated from most code. You can be sure the pure part is very reliable. But still you can not make IO operations and mutations as reliable. For details, you can not modify value or references in functional languages like Haskell and Clojure, you need to use Atom or IORef to use mutable states, which are special data types. And JavaScript just doesn't have any of these.
Back to the React side. JavaScript can be full of mutable states and we hate that. However how can we really program will no side effects and mutable states? You see DOM is mutable, as the UI changes over time, time is somehow changing. We need mutable states, and we need them under strict control.
What do you mean by global state? If you mean the implied global object (window in browser or global in node) then they are not the same as a global state in Flux/Redux architectures.
Either way, the general rule of not modifying something globally available is to save from unintended consequences like naming conflicts, overloading, or mutating shared objects between implicit dependencies. In Flux/Redux the state is meant to be shared across the app and so therefore there are no unintended mutations since it's understood that's what the state is there for. Think of the state as a sort of light, client database for your app.
Hugo Mota
Code Hero
Modifying global state is not bad. When you have a database, you want to modify it's state at some point, right? In the frontend you could use the same analogy. It's not that you don't want to mutate state. You just want to contain and control these mutations. You want the mutations to happen exactly whre you want them, and nowhere else.
It's all about control. If you define a strict protocol to mutate state (like inside some named structure, like actions) and forbid every mutation outside the protocol, you are taking control of how your state will change. This lead to predictable code and meaningful state transitions.
Instead of having a lot of components fighting to change state and producing unpredictable results, you have them calling actions. These actions are simple atomic mutations that makes sense! Example:
REQUEST_LOGIN LOGIN_OK REQUEST_CURRENT_USER RECEIVE_CURRENT_USERYou see these actions firing. You know exactly what's happening and where to solve your problems. That's the whole point. It's even easier to test code like this.