Tech Sheets

InheritedWidgetを使ってDIする

最終更新日:2023-03-28

Flutterの InheritedWidget はツリーの上側にいるウィジェットを定数時間で取得可能にするための特殊ウィジェットです。今回はこれを使って UserRepository のようなオブジェクトを取得できるようにしてみます。

AndroidのJetpack ComposeではCompositionLocalという名称がついています。

InheritedWidgetを継承したクラスを作る

今回はクラス名を AppModule にしてみます。

class AppModule extends InheritedWidget {
  final UserRepository userRepository;
  const AppModule(
      {required this.userRepository, required Widget child, super.key})
      : super(child: child);

  // 更新通知は不要
  @override
  bool updateShouldNotify(covariant InheritedWidget oldWidget) => false;
}

下位ウィジェットで取得する

今回欲しいのはデータの変更通知が必要ない AppModule なので、 getElementForInheritedWidgetOfExactType() で取得します。

class _MyHomePageState extends State<MyHomePage> {
  void _loginClicked() {
    // キャストが必要
    final module = context
      .getElementForInheritedWidgetOfExactType<AppModule>()
      ?.widget as AppModule;
    final repo = module.userRepository;
    final user = await repo.login();
  }
  ...
}

main()で差し込む

runApp() の引数に AppModule() を渡すようにします。差し込みたいオブジェクトはここで作ってしまいましょう。

void main() {
  runApp(
      AppModule(userRepository: DefaultUserRepository(), child: const MyApp()));
}

of()を作る

AppModuleof() を追加して使いやすくします。

class AppModule extends InheritedWidget {
  final UserRepository userRepository;
  const AppModule(
      {required this.userRepository, required Widget child, super.key})
      : super(child: child);

  @override
  bool updateShouldNotify(covariant InheritedWidget oldWidget) => false;

  static AppModule of(BuildContext context) =>
      context.getElementForInheritedWidgetOfExactType<AppModule>()?.widget
          as AppModule;
}

この of() を使うとすっきり書けます。

class _MyHomePageState extends State<MyHomePage> {
  void _loginClicked() {
    final repo = AppModule.of(context).userRepository;
    final user = await repo.login();
  }
  ...
}

一覧に戻る