(タイトルに書いてあるものの、今回は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'), ),