You are hitting the nail on the head here. It’s the primary difference between something like React and the Elm style. In Elm, the state is global, whereas you can have locally defined state in React components. In practice, you often lift state upward in React, so you end up sitting with a “global” state of sorts, and then you pass down, much like you would in Elm.
Some of the state you might want to keep local, you’ve already identified: input data. For some components, it turns out they have an isolated state, which can be run independently of the global state. So rather than having one single state machine driving your application, you have many small state machines driving your application. I have some Erlang experience, and it’s much like that model: processes have their own state, and you communicate by messaging.
So the view is that you have a set of small state machines comprising your system, and because components can be mounted/unmounted, this set is “dynamic” over the course of the application.
Going further, you have ways to “globalize” state in the react component tree which circumvents the tree:
- Context is one example.
- Another useful one is recoil, which implements a subset of the OCaml incremental library. This correspond to ETS tables in Erlang, for instance, which is an implementation of Tuple spaces (Linda, 1986).
All in all, it makes state manipulation in Elm quite explicit, whereas in React state manipulation is component-local and thus more implicit.