Lesson 16 / 25

Lifting State and InheritedWidget

The mechanism under every state library.

Ephemeral versus app state

Ephemeral state (the current tab, an animation, a text field) belongs in a single StatefulWidget. App state (the signed-in user, a cart, settings) is needed by many widgets, so you lift it up to a common ancestor and pass it down. Passing through every constructor ("prop drilling") gets tedious, so Flutter offers InheritedWidget: descendants call context.dependOnInheritedWidgetOfExactType<T>() to read it and are registered as dependents, so when it is replaced and updateShouldNotify returns true they rebuild. Theme.of and MediaQuery.of work this way, and Provider, Riverpod and Bloc build on the same idea of exposing state down the tree.

Share state without the mess

Ephemeral state lives in a widget; app state is lifted up and exposed to the widgets that need it.

Three ideas: lifting state and InheritedWidget, Provider with ChangeNotifier, Riverpod and Bloc.
Figure 6.1 — State lifted up, exposed down, rebuilt where needed.

A minimal InheritedWidget

Exposing a value to descendants.

class UserScope extends InheritedWidget {
  const UserScope({super.key, required this.user, required super.child});

  final User user;

  static User of(BuildContext context) {
    final scope = context.dependOnInheritedWidgetOfExactType<UserScope>();
    assert(scope != null, 'No UserScope found in context');
    return scope!.user;
  }

  @override
  bool updateShouldNotify(UserScope oldWidget) => user != oldWidget.user;
}

// usage deep in the tree
Text('Hi ${UserScope.of(context).name}');

A building intercom

Instead of passing a note through every flat on the way down, the ground floor announces it on the intercom and only the flats that subscribed hear the update.

Quick check: What happens when an InheritedWidget changes and updateShouldNotify returns true?

  • Nothing until hot reload
  • The whole app restarts
  • Widgets that depend on it via dependOnInheritedWidgetOfExactType rebuild
  • Only the root widget rebuilds
Answer

Widgets that depend on it via dependOnInheritedWidgetOfExactType rebuild — Dependents are tracked and rebuilt automatically.