[Flutter] Firestoreからデータを取得する

Firestoreからデータを取得する

今回はFirestoreからデータの取得方法について紹介します。

Firestorの登録データをリアルタイムに取得して画面に一覧表示します。

Scaffoldメソッドの引数名body:以降の記述を変更します。

(変更前)
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),

(変更後)
      body: StreamBuilder<QuerySnapshot>(
        stream: users.snapshots(),
        builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
          if (snapshot.hasError) {
            return Text("エラーが発生しました: ${snapshot.error}");
          }
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const Text("読み込み中...");
          }
          // ドキュメントからデータのリストを作成
          List<QueryDocumentSnapshot> usersList = snapshot.data!.docs;

          return ListView.builder(
            itemCount: usersList.length,
            itemBuilder: (context, index) {
              // nameフィールドを取得
              String username = usersList[index]['name'];
              return ListTile(
                title: Text(username),
              );
            },
          );
        },
      ),

StreamBuilderでFirestoreのデータを監視・再構築する

StreamBuilder<QuerySnapshot>(
//<処理>
)

StreamBuilderを利用すると、ストリームを通じてデータをリアルタイムにUIに反映(再構築)します。そして、<QuerySnapshot>は、StreamBuilderで取得するFirestoreのデータコレクションの型となります。

ストリームを作成

StreamBuilder<QuerySnapshot>(
    stream: users.snapshots()
    //<処理>
)

stream: users.snapshots() は、QuerySnapshotで取得する対象です。snapshots()は、指定したコレクション(users)に対して、ストリームを作成します。コレクション内のドキュメントが追加、削除、変更されるたびに、新しいQuerySnapshotを発行します。

ウィジェットの構築

StreamBuilder<QuerySnapshot>(
    stream: users.snapshots()
    builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
    //<処理>
    }
)

StreamBuilderウィジェットがストリームの新しいイベントを受け取るたびに、新しいAsyncSnapshotインスタンスがbuilder関数に渡されウィジェットの構築を行います。

  • BuildContext context
    現在のビルドコンテキスト
  • AsyncSnapshot<QuerySnapshot> snapshot
    ストリームからの最新のスナップショットを取得して結果を保持します。このsnapshotオブジェクトを使用して、非同期データに基づいてUIを動的に構築・更新することができます。

この builder 関数内では、通常以下のような処理が行われます。

エラーハンドリング

if (snapshot.hasError) {
        return Text("エラーが発生しました: ${snapshot.error}");
}

StreamBuilderbuilder 関数内で一般的に見られるエラーハンドリングの部分です。非同期スナップショットにエラーが含まれているかどうかをチェックします。

ローディング状態の表示

if (snapshot.connectionState == ConnectionState.waiting) {
        return const Text("読み込み中...");
}

StreamBuilderbuilder関数内で非同期データのロード状態を処理しています。特に、データがまだロード中である場合に、ユーザーにローディングメッセージを表示するロジックを提供しています。

  • snapshot.connectionState
    非同期操作の現在の接続状態を表します。
  • ConnectionState.waiting
    非同期操作がまだ「進行中」であることを表します。

このようなローディングインジケーターは、ユーザーエクスペリエンスの観点から重要です。非同期データのロード中にアプリケーションが何も反応しないと、ユーザーは混乱するかもしれません。ローディングメッセージを提供することで、何が起こっているのかをユーザーに知らせ、待機している間にもアプリケーションが応答していることを確認させることができます。

データの表示

List<QueryDocumentSnapshot> usersList = snapshot.data!.docs;

Firestoreから取得したクエリのスナップショットからドキュメントのリストを取得しています。具体的には、クエリスナップショット内のすべてのドキュメントをQueryDocumentSnapshotのリストとして抽出します。

  • snapshot.data: snapshotオブジェクトは、非同期操作からの最新のスナップショットを表し、dataプロパティを通じてQuerySnapshotオブジェクトへのアクセスを提供します。このオブジェクトには、クエリに一致するドキュメントの現在の状態が含まれています。
  • ! (バング演算子): この演算子は、dataがnullでないことを保証します。nullの可能性がある場合にこの演算子を使用すると、もし実際にnullであればランタイムエラーが発生します。このコードの文脈では、snapshot.dataがnullでないことを確信しているとみなされます。
  • .docs: QuerySnapshotオブジェクトのdocsプロパティは、クエリに一致するドキュメントのリストを提供します。このリストには、クエリスナップショット内のすべてのドキュメントが含まれ、それぞれがQueryDocumentSnapshotオブジェクトとして表されます。
  • List<QueryDocumentSnapshot> usersList: 取得されたドキュメントのリストは、usersList変数に代入されます。このリストは後続のコードで処理されることが一般的で、例えばリストビューを生成するために使用されることが多いです。

このコードの目的は、Firestoreのクエリから特定のドキュメントの集合を取得し、それらのドキュメントをプログラムで処理できる形式でアクセス可能にすることです。

リストアイテムの生成

return ListView.builder(
            itemCount: usersList.length,
            itemBuilder: (context, index) {
              // nameフィールドを取得
              String username = usersList[index]['name'];
              return ListTile(
                title: Text(username),
              );
            },
          );

Firestoreから取得したユーザーリスト(usersList)を使用して、リストビューを構築しています。具体的には、ListView.builder ウィジェットを使用して、各ユーザーの名前を表示するリストアイテムを動的に生成しています。

  • ListView.builder: Flutterでリストビューを効率的に構築するためのウィジェットです。大量のアイテムを持つリストでも、画面上に表示されるアイテムだけが構築されるため、パフォーマンスが向上します。
  • itemCount: usersList.length: usersList の長さ(リスト内のアイテム数)を指定します。これによって、リストビューが何個のアイテムを持つべきかを知ります。
  • itemBuilder: (context, index): itemBuilder は、リストの各アイテムを構築するためのコールバック関数です。この関数はリストの各アイテムのインデックスとともに呼び出され、それに対応するウィジェットを返します。
  • String username = usersList[index]['name'];: usersList から指定されたインデックスのユーザーを取得し、そのユーザーのnameフィールドを取り出します。この値は後続のTextウィジェットで表示されます。
  • return ListTile(title: Text(username),);: ListTile ウィジェットは、リスト内の個々のアイテムを表します。ここでは、取得したユーザー名をタイトルとして使用しています。後続のコードでは、このリストアイテムにさらに詳細を追加することができます(例:サブタイトル、先頭アイコンなど)。

全体として、このコードはFirestoreから取得したユーザーデータのリストを取り、それを基にリストビューを構築します。このような動的なリストビューの構築は、多くのモバイルアプリケーションで一般的なパターンであり、Flutterでの実装はこのようになります。

動作確認