Semi-tangential note: React comes with the helpful `React.addons.update`, which implements "immutable data structures" in an extremely simple way.
I'm working on a medium-sized React application where all application state changes go through this function—there's one big state object with all substate, and we don't do any mutation inside of it. We haven't needed to benchmark anything yet, nor do we have any extreme performance requirements.
Since all our state updates work like this, we can use `PureRenderMixin` on all components, which gives us the kind of shallow equality behavior you describe.