I have built my first React application with stateful stores the "normal" way, and now I am looking into using an immutable global state like used in the Este starterkit.
- The state of all stores is kept together in a single immutable data structure
- Components have no state but access data in their render() based on a store getter function
- Stores are also stateless but mutate the global application state for their domain using a cursor.
- The top level app component listens for state changes, and re-renders the whole component tree.
- Components are implemented as "pure" meaning they use shouldComponentUpdate to efficiently figure out of they can be skipped in the re-rendering.
It simplifies the application structure in a few ways:
- Components don't listen to stores and also don't copy store data to their local state. They simply grab their store state on each render.
- The global state is always a snapshot of the whole application, making it easier to debug and adding features like undo trivial.
- The global state seems to simplify isomorphic rendering.
I only read positive things about using immutable data with React, and it is recommended to avoid state in components, so I wonder if there are any disadvantages. I figured there must be because otherwise I don't see why it isn't recommended as the way to structure React apps.
Immutability is new to me, so are there any caveats I should be aware of if I start using this approach in a complex real world app?
The only minor thing I can think of is the use of forceUpdate() as Este is using it, as I've read that it is a synchronous function. Morearty for example seems to defer the updates to the next animation frame in order to batch them, but I consider this an implementation detail / optimization and not some inherit downside of the immutable single state approach.
One advantage of passing data through props is that you can utilize
shouldComponentUpdate
for more performant updates. If you assume data always comes from the parent (e.g. via props), you can effectively prevent a large portion of your component tree from having to rerender. Immutable values make this very nice as you can do reference equality checks inshouldComponentUpdate
relatively high in your component hierarchy.The only other disadvantage I've found when using immutable data with React is that the React developer tools don't work super well with them (they show you the immutable values' underlying data structure instead of a JS-friendly value).
this.state.getIn("[parent, child, index]")
in a component because it increases the possibility of a model change breaking the component code. This is preventable by extensibility (more on that below) or through helper methods, but you certainly lose the simplicity of plain JS members.I know the answer has already been accepted, but I find the primary disadvantage to be that you pass non-plain JavaScript objects into your component code, meaning you cannot use regular JavaScript property accessors when reading values from the Immutable objects passed in via
props
. Instead you have to use Immutable.js' read API. This is a significant trade-off. You cannot keep your use of Immutable.js contained where it belongs, in the store; it has now leaked itself throughout your entire application. This is a pain you may feel when Immutable.js is replaced by the next buzzy Immutability library that has it's own API or is able to use the native property accessors. Additionally, third party code will almost certainly expect plain old JavaScript Objects, so Immutable objects will need to be converted before passing them along. If you plan on introducing Immutable.js into an existing application, it will become unclear very quickly in your component code whichprops
are Immutable and which are JS object, unless you are very disciplined and come up with a naming scheme or some other method that you are consistent with as you pass objects down the rendering chain.