[Flutter] InheritedWidget


## はじめに
FlutterのInheritedWidgetについての記事です。
詳しい原理などは省いて、使い方について言及します。
(詳しい原理については別途記事を作成しようと思います)

## InheritedWidget

データを子Widgetへ効率的に伝えるWidgetです


### 特徴

- 子WidgetはO(1)でInheritedWidgetへアクセスが可能
- InheritedWidgetが提供するデータに変化があった場合、必要に応じて子Widgetのリビルドが可能



## 使い方

- InheritedWidget継承クラスを作成する
- 子WidgetからInheritedWidgetのメソッドを使用してデータを参照する


### InheritedWidget継承クラスを作成する


```dart:inherited_sample.dart

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

  final String text;

  /// InheritedWidget継承クラスを取得する為の関数です
  /// 参照元Widgetから最も近いInheritedWidget継承クラスを取得します
  static InheritedText? maybeOf(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<InheritedText>();
  }

  static InheritedText of(BuildContext context) {
    final InheritedText? result = maybeOf(context);
    assert(result != null, 'No InheritedCounter found in context');
    return result!;
  }

  /// InheritedWidget継承クラスがリビルドされた時に
  /// データを参照しているWidgetをリビルドさせるかを判定するメソッドです
  @override
  bool updateShouldNotify(InheritedText oldWidget) =>
      text != oldWidget.text;
}
```

### 子WidgetからInheritedWidgetのメソッドを使用してデータを参照する

```dart:inherited_sample.dart

class TextDisplayWidget extends StatelessWidget {
  const TextDisplayWidget({super.key});

  @override
  Widget build(BuildContext context) {

    ///
    /// InheritedTextのofメソッドを使用して、textを参照しています
    final text = InheritedText.of(context).text;
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text("InheritedWidgetお試し"),
      ),
      body: Center(
        child: Text(text),
      ),
    );
  }
}
```

### コード全体
```dart:inherited_sample.dart

void main() {
  runApp(const InheritedSampleApp());
}

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

  final String text;

  /// InheritedWidget継承クラスを取得する為の関数です
  /// 参照元Widgetから最も近いInheritedWidget継承クラスを取得します
  static InheritedText? maybeOf(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<InheritedText>();
  }

  static InheritedText of(BuildContext context) {
    final InheritedText? result = maybeOf(context);
    assert(result != null, 'No InheritedCounter found in context');
    return result!;
  }

  /// InheritedWidget継承クラスがリビルドされた時に
  /// データを参照しているWidgetをリビルドさせるかを判定するメソッドです
  @override
  bool updateShouldNotify(InheritedText oldWidget) => text != oldWidget.text;
}

class InheritedSampleApp extends StatelessWidget {
  const InheritedSampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const InheritedText(
        text: "テストだよ",
        child: TextDisplayWidget(),
      ),
    );
  }
}

class TextDisplayWidget extends StatelessWidget {
  const TextDisplayWidget({super.key});

  @override
  Widget build(BuildContext context) {

    ///
    /// InheritedTextのofメソッドを使用して、textを参照しています
    final text = InheritedText.of(context).text;
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text("InheritedWidgetお試し"),
      ),
      body: Center(
        child: Text(text),
      ),
    );
  }
}

```

## 注意点
ofメソッド、というよりもdependOnInheritedWidgetOfExactTypeメソッドは下記では呼ばないようにしましょう

- StatefulWidgetのinitStateメソッド内
    - initStateはStatefulWidgetのリビルドで毎回呼ばれるものではない為です
    - 上位のinheritedWidgetの更新を正しく受け取りたい場合はdidChangeDependencies内で呼ぶ必要があります
- StatefulWidgetのdisposeメソッド内
    - dispose時点ではElementツリーが既に不安定に成っている為です
    - BuildContextを使用して参照を得ているのでElementツリーの状態は常に考慮する必要があると思います


## まとめ
以上がinheritedWidgetの基本的な使用方法です。
今回の例はinheritedWidgetのデータは常に変化しないようになっていますが、StatefulWidget等と併用する事で変更が可能です。

適切ではない点などあればご指摘いただけると幸いです。

## 参考資料
https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html