MOB-LOG

モブおじの記録 (Programming, 統計・機械学習)

Flutterでウィジェットの再構築のために自身のクラスのインスタンスを生成して遷移していたが意味がなかった様子。StreamBuilderでFirebaseのドキュメントを表示していて、値が変更されても表示が更新されないとき。

(タイトルに書いてあるものの、今回はStreamBuilderもDocumentSnapshotも関係ありません)

TL;DR

Firebaseからのデータの再取得と画面の更新のためにウィジェットインスタンスを再生成→新たなインスタンスへ遷移、としてリロードボタンを設置していたが、それでは更新されないので、単純にsetStateを使おう。

事の起こりと問題

Firebaseのデータを表示するために、Firebase.instanceで目的のデータを取得して、取得したドキュメントをStreamBuilderで処理していました。Firebaseでの値の変更を表示に反映するために、ReloadボタンをScaffoldのFloatingActionButtonに設定し、押すと自身のウィジェット (ItselfWidget) のインスタンスを新たに生成してcontextをそれに遷移するようにしていました(ここに間違いがあります)。

floatingActionButton:
  FloatingActionButton.extended(
    onPressed: () {
      /// reload the page
      **Navigator.of(context)
          .pushReplacement(MaterialPageRoute(builder: (context) {
        return ItselfWidget(
          title: this.title,
        );
      }));**
    },
    heroTag: 'reloading',
    tooltip: 'Reload recipe',
    icon: const Icon(Icons.replay_outlined),
    label: const Text('Reload'),
  ),

ただ、Firebaseの値を更新した後にReloadボタンを押しても、変更した内容は表示されません(動画の通り、画面遷移を伴ってRatingを追加したはずなのに評価の欄の値は変更されない。他の同じデータを参照する画面では値が更新されているのに、戻ってみると更新されていない。)。

なぜ?Widgetを再生成しているのに。

解決策

ただただsetState()して再構築する必要があった様子。逆に言うと自身と同じWidgetインスタンスを生成してNavigatorを使って遷移するだけでは意味がない。setStateでリビルドの要求を出すと@override build()が再度実行されて再描画されるのは当たり前だけど、Widgetインスタンスを生成→遷移では更新されない(buildされない?)のは初見だった。

floatingActionButton:
  FloatingActionButton.extended(
    onPressed: () {
      reload the page
      **setState() {};**
    },
    heroTag: 'reloading',
    tooltip: 'Reload recipe',
    icon: const Icon(Icons.replay_outlined),
    label: const Text('Reload'),
  ),

学び

  • setStateでリビルドの要求を出すと@override build()が再度実行されて再描画されるが、Widgetインスタンスを生成→遷移では更新されない(buildされない?)