LoginSignup
7
3

More than 3 years have passed since last update.

FlutterでFirestoreのデータをFutureBuilderを使って非同期で取得する

Posted at

目的

今まではFirestoreから取得したデータを取得できたときにsetState()で再描画していたのですが、FutureBuilderを使えばStatelessWidgetにできて、簡単にきれいに書けることを知ったのでまとめてみます。
setState()で再描画するだけの処理にするのではなく、エラー分岐やデータ取得状況もわかるFutureBuilderを使ったほうがUXも高めれて良さそうなので積極的に使っていきたいですね。

環境

今回使っているFirestoreのバージョンは0.14.0です。
firebase_coreは0.5.0です。

pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  firebase_core: ^0.5.0
  cloud_firestore: ^0.14.0

非同期処理で使う関数

まずはFirestoreからデータを取得するFutureオブジェクトを作成します。
今回は指定のドキュメントIDのデータを取得するという簡単な関数にします。
コレクションIDとドキュメントIDを自身のものに置き換えてください。

Future<Map<String, dynamic>> getDocumentData() async {
  DocumentSnapshot snapshot = await FirebaseFirestore.instance
      .collection('コレクションのID')
      .doc('ドキュメントのID')
      .get();
  return snapshot.data();
}

FutureBuilderの使い方

Widgetのbuild()にFutureBuilderを追加します。
今回はScaffoldのbodyに直接置いていますが、実際はFirestoreのデータを表示したいところに追加してください。

FutureBuilderのfutureプロパティには作成したFutureの関数を指定します。
builderプロパティには(context, snapshot) { }を指定します。
一度、builderプロパティの関数が呼ばれます。
非同期処理が終わったら、再度builderが呼ばれて、エラー処理やデータが取得できなかったときに適切なWidgetを表示するようにしています。

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text('Flutter × Firestore'),
    ),
    body: FutureBuilder(
      future: getDocumentData(),
      builder: (context, snapshot) {
        // 取得が完了していないときに表示するWidget
        if (snapshot.connectionState != ConnectionState.done) {
          // インジケーターを回しておきます
          return const CircularProgressIndicator();
        }

        // エラー時に表示するWidget
        if (snapshot.hasError) {
          print(snapshot.error);
          return Text('エラー');
        }

        // データが取得できなかったときに表示するWidget
        if (!snapshot.hasData) {
          return Text('データがない');
        }

        // 取得したデータを表示するWidget
        return Text('${snapshot.data}');
      },
    ),
  );
}

取得したsnapshotの使い方

snapshotはAsyncSnapshot型なので、
FutureBuilderで取得したデータはsnapshot.dataでアクセス出来ます。

今回取得できるデータはFirestoreのデータなのでsnapshot.data['key']のようにFirestoreで指定したKeyを書けば取得できます。

builderプロパティでsnapshotに(context, AsyncSnapshot> snapshot) { }のように型を指定することも出来ます。

クラス全体のコード

class TestWidget extends StatelessWidget {
  Future<Map<String, dynamic>> getDocumentData() async {
    DocumentSnapshot snapshot = await FirebaseFirestore.instance
        .collection('コレクションのID')
        .doc('ドキュメントのID')
        .get();
    return snapshot.data();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter × Firebase'),
      ),
      body: FutureBuilder(
        future: getDocumentData(),
        builder: (context, snapshot) {
          // 取得が完了していないときに表示するWidget
          if (snapshot.connectionState != ConnectionState.done) {
            return const CircularProgressIndicator();
          }

          // エラー時に表示するWidget
          if (snapshot.hasError) {
            print(snapshot.error);
            return Text('エラー');
          }

          // データが取得できなかったときに表示するWidget
          if (!snapshot.hasData) {
            return Text('データがない');
          }

          // 取得したデータを表示するWidget
          return Text('${snapshot.data}');
        },
      ),
    );
  }
}

さいごに

Firestoreからデータを取得するたびにsetState()を呼ぶよりも、FutureBuilderを使ったほうがコードがきれいに書けて、取得状況もユーザーに知らせられるのでとても良いWidgetだと思います。
簡単に実装できるのでぜひ使ってみてください!
もし間違っている所があれば、ぜひ教えて下さい!

7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3