I grumpily ignored the comments about mobx for a while, then finally broke and used it on a small side project. The results were...

...disheartening. Because (at least for my team and the specific projects we do), mobx was much much better.

(Disclaimer: We use React to incrementally replace/upgrade pages and panels in a very large admin console. So we have a ton of very small apps that share a lot of concepts, but are still distinct apps. Obviously this multiplies the amount of boilerplate we have to deal with compared to if we were using a single "monolithic" SPA.)

Key advantages:

1) Way, way, way less boilerplate. With redux you soon grow used to the dance of adding a new sub-reducer, a new batch of constants, a new batch of action creators, then wiring up the new action creators to your container, wiring up the new state sub-trees to your container, and boom, now you've got some props that represent your data, and some functions you can call to change that date.

With mobx, you add some new observers and (optionally) some actions to change those observers and...you're done. It feels odd at first; when you're used to redux you're used to setting up a new app (or coming to grips with an old one you haven't touched in a while) as a very elaborate process. With mobx the "skeleton" is done before you even really start. It's almost worrying.

2) Redux has some very specific ways it wants you to structure your project, and some of them are quite good. A junior dev might struggle to grasp what's required to set it up from scratch, but I think for an intermediate dev it can be quite helpful. It strongly forces you to make some good choices about data flow, seperation of concerns, logging, etc. But for a senior dev it can be a little...limiting. I actually know what I'm doing, and sometimes the right answer doesn't 100% fit into the Redux way of doing things, even if the "redux way" is great 95% of the time.

Mobx allows a lot more flexibility. I suspect that could be a drawback in some cases too, but for this particular case, it's quite nice. You can actually implement a number of different patterns on top of mobx, including a redux style state tree, or (as we've done) some Backbone/ActiveRecord style models. Which obviously have a lot of limitations and are great for everything, but are really great for our specific use case.

3) On a related note, redux really needs data to be normalized; you end up devoting a remarkable amount of time to normalizing data (using normalizr or whatever) and then de-normalizing it in your components to handel relations properly, and then figuring out how to modify your normalized state tree in your reducers based on actions triggered in your denormalized component tree. Totally doable, but a pain.

Mobx makes it easy to use references, avoiding the entire issue.

4) Closely related to the last two points, components written with redux in mind often end up with very extensive lists of props, because they end up needing a little bit of data from six different reducers, plus a dozen action creators. It works. It's fine! But...

...with mobx, at least the way I'm using it, you can generally get away with just passing in the relevant model, You keep ending up with situations where you pass your ProductList model into your ProductList component, which maps over the Product models it contains and passes them into a component called Product. Your actions are just methods on the model class. Components with 1-2 props are easier to reason about and (in my experience) easier to test.

All of which is basically just 4 different ways of saying that for me, it lets me type a lot less (which is good), but most of all it lets me think more about the problem I'm trying to solve, and less about the libraries I'm using (which is key).