The most important feature of an imperative program is the state and their modifications.
ReactJs encourages as much functional style of programming (e.g. using purity, higher-order functions). I want to know if using immutable state in ReactJs this characteristic still as an imperative feature or could be considered as functional "style of state"?
Theoretically, what is the difference between the React state and state in pure imperative programs?
Theoretically, what is the difference between the React state and state in pure imperative programs?
The whole purpose of updating state (using this.setState
) in React is to notify the component that state has been updated, and a re-render is required.
But, ultimately, if you want to change from state A to state B in React, you do so inside event handlers, which can be done imperatively, if you like, but it has to be done without actually changing the initial state. e.g.
// OK
let foo = this.state.foo;
foo = deriveSomeValue(foo);
this.setState({ foo });
// BAD
this.state.foo = deriveSomeValue(foo);
this.setState(this.state);
In the first example (OK), sure, you can see some level of impurity; foo
is modified, but at least the original state is not.
In the second example (BAD), we have the same level of impurity, but worse; we're directly modifying the current state, which can yield unpredictable results. I see too many Stack Overflow posts with people asking "why isn't things rendering properly when I do X with this.state
???" In other words, this immutability paradigm is enforced for pragmatic reasons; which is, it is how React was designed to work, and any other ways yields undefined behaviour (on a case-by-case basis).
Another example that can yield unpredictable result:
const foo = this.state.foo;
foo.someProperty = getSomeValue();
this.setState({ foo });
Which, in this case, state is still updated before ever notifying React. (This has to do with the fact that objects are explicitly referenced, rather than being implicitly copied.)
Sure, you can go from state A to state B in React in an imperative style inside event handlers, but you have to ensure that the initial state does not get modified directly. If you absolutely see that there needs to be some complex modifications involved, then I recommend that you perform a deep copy of the object, and then doing the necessary modifications that way. The following is perfectly fine:
const foo = cloneObject(this.state.foo);
// `cloneObject` is an entirely contrived function. You'll have to pick a
// deep copying library. Google around for "JavaScript deep copying"
foo.someProperty = getSomeValue();
this.setState({ foo });
Alternatively, you can use immutable data structures, so that if you are (what can be semantically referred to as) modifying a property directly, it yields an entirely new object without necessarily modifying the original. A good library for it would be (as you mentioned) ImmutableJS.
let foo = this.state.foo;
foo = foo.set('someProperty', getSomeValue());
this.setState({ foo });