See the link provided by Günter above. If you have thirty minutes watch Brian Egan's DartConf 18 presentation: Keep it Simple, State. Also see Brian's example code here. He shows the same app coded using InheritedWidget with a Controller, and with Flutter Redux.
Here's a example of a single InheritedWidget from a simple app of mine...
class StateContainer extends InheritedWidget {
final List<Membership> memberships;
final IntFunction getNextIndex;
final VoidMembershipFunction updateMembership;
final VoidIntFunction deleteMembership;
const StateContainer({
this.memberships,
this.getNextIndex,
this.updateMembership,
this.deleteMembership,
Widget child,
})
: super(child: child);
static StateContainer of(BuildContext context) {
return context.inheritFromWidgetOfExactType(StateContainer);
}
@override
bool updateShouldNotify(StateContainer oldWidget) {
return true;
}
}
I pass in my MaterialApp as the child. A high proportion of the tree then becomes stateless as it has access to the data and methods if the StateContainer. You could think of these as your model and controller in one. Build methods in the tree often start with...
@override
Widget build(BuildContext context) {
final StateContainer container = StateContainer.of(context);
to get access to them.
You are right that a single InheritedWidget becomes unwieldy quickly - which is where you might invest in exploring Redux - see the last 10 minutes of the talk. In my experience, the area that gets messiest quickest is the updateShouldNotify method when ends up comparing all the member variables. (In this simple example there is only one member variable, and setState only gets called when it changes, so it's trivially always true.)