The venerable master Qc Na was walking with his student, Anton. Hoping to prompt the master into a discussion, Anton said “Master, I have heard that objects are a very good thing – is this true?” Qc Na looked pityingly at his student and replied, “Foolish pupil – objects are merely a poor man’s closures.”
Chastised, Anton took his leave from his master and returned to his cell, intent on studying closures. He carefully read the entire “Lambda: The Ultimate…” series of papers and its cousins, and implemented a small Scheme interpreter with a closure-based object system. He learned much, and looked forward to informing his master of his progress.
On his next walk with Qc Na, Anton attempted to impress his master by saying “Master, I have diligently studied the matter, and now understand that objects are truly a poor man’s closures.” Qc Na responded by hitting Anton with his stick, saying “When will you learn? Closures are a poor man’s object.” At that moment, Anton became enlightened.
MobX takes normal data (usually class properties) and makes it observable, via an annotation. That very much appears to be what the @State annotation in the Swift code is doing, though I don't know for sure.
setState is a totally special container for data; while it technically lives in a class member (this.state), it can only be modified via setState. It isn't observable, so much as setState just internally triggers a render directly.
useState is different because your state lives out somewhere in React's core framework, associated with your function only through a value and a callback. It doesn't live in your function's local scope itself, because it would get lost if it did. It's very weird and funky because the whole point of non-class components is for them to be pure functions which have no state. useState is this shortsighted workaround for that self-imposed limitation.
Redux, finally, is different because its new states are determined as a pure function of the current state and some change. It's the polar opposite of MobX's mutable-observables pattern. Neither is strictly better, but they're as different as can be.
@observable/useState/React.Component.state are all conceptually identical, just with varying implementations of the magic. All of them summon an observable value from the void and provide some method of updating said observable.
That said, @State seems most identical to useState -- it provides an observed value which you use $/.binding to update.
> It's very weird and funky because the whole point of non-class components is for them to be pure functions which have no state.
That's a false assumption, that's not the "point" of functional components. Functional components were always pure simply because there was no way to make them stateful. There are distinct benefits for using stateful functional components over classes -- mainly less boilerplate and abstractable/re-usable state functions.
> What's the difference between a class and a function with local state?
Practically nothing, especially since it is stored in objects and the code uses a lookup table to figure out which ones are part of your function's "this" (essentially), IIRC from reading the code. The similarity to how one implements objects/classes has been good for some laughs.
(Semantics aside, either way this behavior is implemented in React via useState or setState, MobX has nothing to do with it)