【Flutter】flutter_hooksのuseEffect内でInheritedWigetを呼ぶとエラーになる対応

Flutter状態管理

Flutterでflutter_hookuseEffectを使用していると何も気にせず処理を入れると下記のようなエラーが表示されます。

日本語でのuseEffectの解説があまりなかったのでそちらについての解説をしていきたいと思います。
参考になれば幸いです。

エラー内容

check Cannot listen to inherited widgets inside HookState.initState. Use HookState.build instead

 HookState.initState 内で継承されたウィジェットをリッスンできません。代わりに HookState.build を使用してください。
【日本語訳】

参考コード(エラーになる)

    void showTestDialog() {
      showDialog(
        context: context,
        builder: (BuildContext context) {
          return const TestPage();
        },
      );
    }

    // ここでエラー
    useEffect(() {
        showTestDialog();
      return;
    }, []);

ポイント

ポイントとしては、

  • useEffett内でInheritedWidgetを呼ぶとエラーに
  • 代わりにHookState.build を使用してね

のようなイメージです。

useEffett内でInheritedWidgetを呼ぶとエラーに

InheritedWidgetとは

そもそもinheritedWidgetとは下記のようなものです。

  • ウィジェットツリー全体または一部に対してデータを効率的に共有するために使用される特別なウィジェット
  • 実際のアプリケーションでは、InheritedWidgetを直接使用することは少ない

Riverpodの場合

Riverpodの場合は、

  • InheritedWidgetの制限を克服するために設計された新しい状態管理の仕組み
  • 特定のツリー外でのデータ共有が困難というデメリットがある

Flutter公式のInheritedWidget

InheritedWidget class - widgets library - Dart API
API docs for the InheritedWidget class from the widgets library, for the Dart programming language.

このInheritedWidgetをuseEffetct内で呼ぶとエラーになります。

代わりにHookState.build を使用してね

代わりに「HookState.build を使用してね」とのことでした

つまり

  • useEffectやuseStateを正しく機能させるためには、build メソッドの呼び出し中にフックを使うべき

ということですね。

対策

WidgetsBinding.instance.addPostFrameCallbackを使う

WidgetsBinding.instance.addPostFrameCallbackを使用することで以下のようなことが可能になります。

  • ウィジェットツリーが完全に構築された後に、特定の処理を実行するために利用されます
    • ウィジェットのビルドが完了し、フレームが描画された後にコールバックを実行
    • 必要な状態が確実に初期化されたタイミングで処理を実行できる

ただ、addPostFrameCallbackはあくまでウィジェットツリーの描画後に一度だけ処理を行いたい場合に使うのがベストです。

参考コード

    useEffect(() {
      WidgetsBinding.instance.addPostFrameCallback((_) {
        showTestDialog();
      });
      return;
    }, []);

状態の変化に基づいて処理を実行したい場合には、useEffectやbuild 内でのフック使用が適切です。別途他の解決方法についても追記できればと思います。

最後に

useEffectについて簡単に解説いたしました。さらに深ぼった記事についても別途記事として書けたらと思います。

ではまた。

コメント

タイトルとURLをコピーしました