どーも、ぐるたか@guru_takaです。
ボタンを押すと、数字がカウントされていくサンプルをInherited Widgetで書き直しました。

setStateが呼び出されると、必要なWidgetのみ、ビルドされるようになっています!

ここでは、サンプルに沿って、Inherited Widgetの使い方を紹介します。サンプルソースは下記リンクにありますので、よろしければご覧ください。
参考
gurutaka/inherited_widget_sampleGithub
目次
InheritedWidgetとは?
InheritedWidgetは、ツリーの配下に対し、効率的に情報を伝えるWidgetのクラスです。下の例が最もわかりやすいので、引用します。
すごく簡単な図ですが、Cボタンを押下したら、Stateが変更されて、Aのテキストだけがリビルドされて表示が変わる。 
このように、InheritedWidgetを使うと、効率的に情報をツリー下に渡せます!
処理の主な流れ
今回のサンプルの処理の流れに下にまとめてみました。
setStateが呼び出されるStatefulWidgetがリビルドinherited widgetが呼び出され、子widgetに通知するinheritFromWidgetOfExactTypeでビルドした子widgetのみ通知がくるSTEP1:ボタン押すと、setStateが呼び出される
class WidgetIncrementBtn extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final HomePageState state = HomePage.of(context, rebuild: false);
    return FloatingActionButton(
      onPressed: () => state._incrementCounter(),
      tooltip: 'Increment',
      child: Icon(Icons.add),
    );
  }
}
final HomePageState state = HomePage.of(context, rebuild: false);が最初に呼びされます。ボタンの見た目は何も変わらなくてOKなので、引数rebuild: falseにすることで、ボタン自体をリビルドしないようにしてます。
関数HomePage.ofはこちらです。
class HomePage extends StatefulWidget {
  const HomePage({Key key, this.child}) : super(key: key);
  final Widget child;
  @override
  HomePageState createState() => HomePageState();
  static HomePageState of(BuildContext context, {bool rebuild = true}) {
    return rebuild
        ? (context.inheritFromWidgetOfExactType(_InheritedWidget)
                as _InheritedWidget)
            .data
        : (context
                .ancestorInheritedElementForWidgetOfExactType(_InheritedWidget)
                .widget as _InheritedWidget)
            .data;
  }
}
inheritFromWidgetOfExactTypeを使用してビルドすると、自動的にStateの変化が通知されるようになります。一方で、ancestorInheritedElementForWidgetOfExactTypeを使うと、通知がいかないようになります。
カウントアップ用のボタンは見た目の変化はないので、リビルドの必要がありません。そのため、引数rebuild: falseを渡しています。
そして、_incrementCounter関数が呼び出され、数字がカウントアップします。
STEP.2:StatefulWidgetがリビルド
STEP1でsetStateが呼びされ、StatefulWidgetがリビルドされます。
class HomePageState extends State {
  int counter = 0;
  void _incrementCounter() {
    setState(() {
      counter++;
    });
  }
  @override
  Widget build(BuildContext context) {
    return _InheritedWidget(
      child: widget.child,
      data: this,
    );
  }
}
このとき、_InheritedWidgetに子widgetとHomePageState自体のデータを渡します。
class _InheritedWidget extends InheritedWidget {
  _InheritedWidget({
    Key key,
    Widget child,
    this.data,
  }) : super(key: key, child: child);
  final HomePageState data;
  @override
  bool updateShouldNotify(InheritedWidget oldWidget) => true;
}
STEP.3:inherited widgetが呼び出され、子widgetに通知する
ここでStateに変化があると、bool updateShouldNotify(InheritedWidget oldWidget) => true;が発火します。
そして、HomePageState of(BuildContext)があるWidgetに通知がいきます。
このサンプルでは、カウントアップされた数字を表示するWidgetNumTextに通知がいきます。
class WidgetNumText extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final HomePageState state = HomePage.of(context);
    return Text(
      '${state.counter}',
      style: Theme.of(context).textTheme.display1,
    );
  }
}
STEP.4:カウント数を表示するテキストがリビルド
そして、WidgetNumTextがリビルドされ、カウントがアップされた数字が表示されます!
最後に
以上になります。これからInheritedWidgetを学ぶ方の参考になれば幸いです。
また下記2つのリンクが凄く丁寧でわかりやすかったので、ぜひ一度目を通してみると良いと思います!
参考
QiitaInheritedWidget/InheritedModelとは何か
参考
InheritedWidget を完全に理解するMedium



コメントを残す