ふくしま

ソフトウェアエンジニア

FutureBuilder の future に非同期処理の関数を直接入れていたら、setState するたびに非同期処理が走った話。

やりたかったこと

setState しても二度目の非同期処理が走らない状態にしたかった。

起こった問題

以前書いたFutureBuilder で future に入れた値はどこに行くのか分からなくて四苦八苦した話。でやったように、 future に直接、非同期処理の関数を入れていたら、setState するたびに非同期処理が走ってしまった。

例えば、チェックボックス WidgetonChanged するときに setState でチェックを入れたかのフラグを切り替えたりするけど、 チェックボックスにチェックを入れるたびに、くるくる画面になってしまうイメージ。これは良くない。

解決策

initState に非同期処理の結果値を入れたら解決した。 どういうことかというと以下のコードがわかりやすいだろう。

class _SampleState extends State<Sample> {
  bool isChecked = false;
  late Future<String> _version; // Future型のフィールドとしてクラスに定義しておく

  @override
  void initState() {
    _version = _getVersion(); // 非同期処理をフィールドに入れる
    super.initState();
  }

  Future<String> _getVersion() async {
    return await sampleService.getVersion(); // 非同期処理
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: _version, // initで入れたフィールド
      builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
        Widget childWidget;
        if (snapshot.connectionState == ConnectionState.done) { // 非同期処理完了時
          if (snapshot.hasError) { // 非同期処理でエラーが起きた時
            childWidget = _errorDisplay();
          }
          childWidget = Text('${snapshot.data}'); // 非同期処理で得られた結果。
        } else {
          childWidget = const CircularProgressIndicator();
        }
        return childWidget;
      },
    );
  }
}