⚠️

[エラー]Don't use 'BuildContext's across async gaps.

2024/07/10に公開

タイトルのようなエラーが出てたので、修正しました。

このエラーが出た場面

StatefulWidgetを継承したクラス内の非同期処理で、awaitの後にcontextを使用したpush処理を記述した際にエラーが出現した。

void getLocationData() async {
    dynamic weatherData = await WeatherModel().getLocationWeather();

      Navigator.push(
        // ▼error
        context,
        MaterialPageRoute(
          builder: (ctx) => LocationScreen(
            data: weatherData,
          ),
        ),
      );
  }

和訳

Don't use 'BuildContext's across async gaps.
Try rewriting the code to not use the 'BuildContext', or guard the use with >a 'mounted' check.

エラー全文和訳すると下記のようになる。

BuildContextを非同期のギャップで使用しないこと。
BuildContext'を使わないようにコードを書き換えるか、'mounted'チェックで使用をガードする。

なぜ、このようなエラーが出たか

エラーの文言から、awaitの処理の後にcontextを使用した処理を行おうとしたことが原因。
contextというのは、構築されているWidgetの最新の状態(=WidgetTree内の位置付け)
を管理しているもの。
awaitで次の処理の再開まで時間がかかる。その最中で、Widgetが無効にされている(現在のWidgetが破棄される)とcontextを使用した処理でエラーになるため、注意されている。

どうすれば解決できるか

エラー文の通り、'mounted'を使ってチェックする。

'mounted'チェックで使用をガードする。

mountedとは

Stateオブジェクトが、最新の状態で構築されているか(=WidgetTree内に存在するか)どうかを確認する。
有効ならtrue,、無効ならfalseを返す。

コード修正

if文でmountedのtrue,faleseを確認して、Navigator.push処理させる。

void getLocationData() async {
    dynamic weatherData = await WeatherModel().getLocationWeather();
    if (mounted) {
      Navigator.push(
        context,
        MaterialPageRoute(
          builder: (ctx) => LocationScreen(
            data: weatherData,
          ),
        ),
      );
    }
  }

Discussion