#目的
今まではFirestoreから取得したデータを取得できたときにsetState()で再描画していたのですが、FutureBuilderを使えばStatelessWidgetにできて、簡単にきれいに書けることを知ったのでまとめてみます。
setState()で再描画するだけの処理にするのではなく、エラー分岐やデータ取得状況もわかるFutureBuilderを使ったほうがUXも高めれて良さそうなので積極的に使っていきたいですね。
#環境
今回使っているFirestoreのバージョンは0.14.0です。
firebase_coreは0.5.0です。
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だと思います。
簡単に実装できるのでぜひ使ってみてください!
もし間違っている所があれば、ぜひ教えて下さい!