> At that point, it seems you're not necessarily any better off than you would be with a more traditional, event-driven architectural style
Not having to implement the dom state updates and rAF update batching are fairly big wins. The only other way I know of doing this is via data binding and the difference there is that individual updates are more efficient but establishing the bindings is usually O(n_size_of_input) and in practice every app I've worked on that did data binding eventually broke the approach. Having the shouldComponentUpdate escape hatch has allowed me to push much larger volumes of data through the system without it breaking.
I've implemented a number of reasonably complex apps but the two largest have been on immutable datastructures where React's assumptions always hold unless you screw something up. The largest non-immutable app I've written was a 25k LoC layout builder where the two shouldComponentUpdates for vdom pruning were pretty straightforward.
Good luck with your app.