React isn't magically fast, it's just O(n_size_of_diff). Getting it to perform well here requires you to figure out how to prune the size of the diff. You're doing it by splitting the app state into finer grained trees (each tree is pruning the branches it's not listening to) but any gains you're picking up from doing this could be done on the single root solution with appropriate shouldComponentUpdate methods.
The alternative (and easier) way of reducing the diff size is to simply window your data before passing it into the render, which can work for things like grids and lists but doesn't sound like your problem.
You also need to occasionally reshape your data to make the diff smaller. I work on a search app that thrashed for 1.2s every time new search results came in. The problem was that the results were invalidating a recursive menu component which was re-rendering 4 times per update. Avoiding the invalidation fixed the specific delay but the menu was still slow. Switching the menu's data organization from at tree of objects with `open` attrs to a static tree + open path and only rendering the visible nodes solved the perf problems in the app.