fwiw it's possible to achieve all of these benefits in vanilla react using javacsript with regular javascript data structures
* single mutable ref to normalized app state
* cursors for encapsulation and modularity
* O(1) deep equality checks
* fastest possible react performance
source: I have done it in two large react apps, but i have not documented it yet. Blog post coming soon.
Interestingly, as your app state gets bigger, you are actually forced to use something like cursors for all state updates, for performance reasons. Naive immutability in javascript means clone-before-modify, which is far too slow when your state values are large. It quickly bubbled up in our profiler. Funneling all immutable updates through a cursor means the cursor can use structure sharing on the state value, skipping the defensive clone and preserving reference equality for equal subtrees. Also afaik, implementing a general shouldComponentUpdate (edit: in js) without something like cursors is not possible, because you need === equality for onChange props.
One question I have for you: In those large React apps, did you put all state changes in the big single central app state data structure?
I'm currently building an app where the core state is simply a tree of plain old mutable JS objects. We have all the expected disadvantages (mostly: no easy shouldComponentUpdate), but things are easy to reason about, otherwise. We found that stuff like "has the user expanded a dropdown" or "which auto-completeable search term has just been entered" works perfectly in a local component's setState. The idea is, basically, anything that the user doesn't care losing when navigating away from the current screen can go in a local component's state. This seems to go entirely against the functional immutability idea, but it significantly reduces the amount of updates we need to do to our big central data structure.
I'm going to build a new thing and I'm considering going the nice functional way. However, I can't see any downsides to using directly mutable state to simple, local, unimportant stuff.
Would you do it like that? Or would you avoid component state altogether and go with props only?
We also use component local state for things like that, and David Nolen (Om) likes component local state too. But the state goes up top by default. The biggest reason for this is because you might want to attach a diagnostic component to your state (e.g. a json editor [1]), and you don't want to have to change the shape of your state to do that.
There are like six implementations of cursor-y things for React on the internet in varying degrees of quality. I feel pretty strongly that a quality cursor implementation should make its way into react addons before 1.0.
You can find mine from my github but it is not yet ready for public consumption. As far as I am aware mine is the only one that allows === checks on value & onChange. (I will find time to release and document it in the next week)
refs are not the highest performance reference type due to transactional semantics. ClojureScript already has efficient mutability in the form of atoms and transients. You can actually build a transient vector faster than you can build a mutable JavaScript array in recent builds of V8. I actually demo'ed this at JSConf. Fun stuff.
Interestingly, as your app state gets bigger, you are actually forced to use something like cursors for all state updates, for performance reasons. Naive immutability in javascript means clone-before-modify, which is far too slow when your state values are large. It quickly bubbled up in our profiler. Funneling all immutable updates through a cursor means the cursor can use structure sharing on the state value, skipping the defensive clone and preserving reference equality for equal subtrees. Also afaik, implementing a general shouldComponentUpdate (edit: in js) without something like cursors is not possible, because you need === equality for onChange props.