I would like to encourage you to take a look at MobX State Tree.
I have been using it for two weeks (though I have been using MobX - the underlying library for a while). Besides a few hiccups the experience has been delightful.
Just like Redux, MST encourages you to structure your domain model in terms of a single state tree. Components can selectively observe parts of this tree and the official react integration library will take care of re-rendering relevant components whenever the relevant models change.
However unlike Redux, you don't have to deal with the boilerplate of defining reducers and your application logic does not get split out between actions (and thunks or sagas etc.) and reducers. Plus you don't have to worry about ensuring immutability of the tree.
Coming from an object-oriented background, I have found MST's approach of closely coupled models and action methods (which are the only means to alter the state of these models) to be a much more intuitve solution.
It may be useful to think of MST as an ORM for a hierarchical in-memory database that powers your frontend and serves as the single source of truth.
Your migration process would be something like the following:
setState invocations with model level actions which can be shared across components.Perhaps in the shorter term the biggest win is that once you structure your state as models (along with associated computed values and views), you can almost entirely eliminate most of the shouldComponentUpdate functions across your codebase.
Instead of writing code that compares previous props and new props (or state), you can declare the data which your component depends on at the most granular level, and the sophisticated reactive model takes care of re-rendering your components whenever these specific models change. This works quite efficiently in practice and fits very well with React's declarative model.
Another quick win is that having asynchronous actions as first class citizens means that you don't have to choose between a dozen libraries with varying levels of complexity and flexibility whenever your applications needs an asynchronous operation. In javascript world, treating asynchronous logic as something that needs special handling through third party solutions has always seemed weird to me when working with Redux.
MST has many more awesome features which are outlined in the Introductory docs and MST contributors are really helpful. Almost all benefits for which you may be inclined to choose Redux are available with MobX as well. The only caveat being that MobX is internally significantly more complex than Redux.
In the longer term, I would encourage you to look into typescript as well (unless you are already using it). MST works great with TS (it is itself written in TS) and uses some awesome features of TS to seamlessly unify the benefits of static and runtime verifications.