【Flutter】setStateをinitStateの中で呼ぶ時の注意点

Flutter

こんにちは。趣味グラマのNobu(@nm_aru)です。

Flutterで思わぬ罠があったので、備忘録として残しておきます。
趣味グラマしか引っかからない罠かもしれませんが…。

画面間を素早く行き来するとエラーが起きる

何を言っているのか分かり難いかもしれませんが…

例えば

A画面:情報の一覧をリスト表示する画面
B画面:A画面で選択した情報の詳細を表示する画面

という物があったとします。

B画面では、A画面から渡された情報をもとに、インターネット上から情報を取得し、自らの画面に表示します。

B画面のソースコードは、以下のようになります。

この時、普通にA→Bと遷移しているだけなら何も起きないのですが、Bに遷移してすぐにAppBarの戻るボタンなどでAに戻った場合、以下のエラーが発生する場合があります。

FlutterError (setState() called after dispose(): _HogeInfoState#6bdf7(lifecycle state: defunct, not mounted)
This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback.
The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.
This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose().)

エラー内容を読むと、これだろうなという事がしっかり書いてあります。

This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree

意訳:Widget Treeに存在しないWidgetのStateオブジェクトに対してsetState()を呼び出したらエラーになるよ

今回は、別にアニメーションやタイマーを使っている訳ではないですが、非同期処理を行っていたため、恐らく以下の流れでエラーになったのだと思われます。

  1. A画面→B画面に遷移する
  2. B画面のinitState内で_loadData()という非同期処理を実行する
  3. 2の非同期処理を実行中に、戻るボタンでA画面に戻る
  4. この時点でB画面のWidgetはWidget Treeから無くなる
  5. _loadData()の処理が終わり、B画面のWidgetのStateオブジェクトに対してsetState()を呼び出し、エラーが発生する

解決法についても、先ほどのエラーメッセージにしっかり書いてあります。

Another solution is to check the “mounted” property of this object before calling setState() to ensure the object is still in the tree.

意訳:setState()を呼ぶ前に、Stateオブジェクトの”mounted”プロパティをチェックすれば、そのWidgetがWidget Treeに存在しているか分かるよ

mounted property - State class - widgets library - Dart API
API docs for the mounted property from the State class, for the Dart programming language.

という訳で、早速ソースコードを以下のように修正し、確認してみたところ、エラーは起きなくなりました。

まとめ

Flutterはエラーが起きると、原因と解決法をエラーメッセージ内に表示してくれるので、とても助かります。

仮に直接解決に繋がらなくても、調べるための手掛かりになりますし。

ReactNativeからFlutterに鞍替えして良かったなと思う点の1つですね(^^)

コメント

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