7K12 blog

猫でも分かる何か

web54改 Cloud Firestore

  • 参考

https://www.flutter-study.dev/firebase/cloud-firestore-try
https://zenn.dev/maropook/articles/f82c98a56b14ca
https://note.com/hatchoutschool/n/na654d6dc5a53

pubspec.yaml

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.2
  firebase_core: ^1.0.1
  cloud_firestore: ^3.1.13 
  cloud_firestore_web: ^2.6.13
dependenciesに
firebase_core: ^1.0.1
cloud_firestore: ^3.1.13 
cloud_firestore_web: ^2.6.13
を追加する

index.html

<!DOCTYPE html>
<html>
<head>
(略)
</head>
<body>
<script type="module">
  // Import the functions you need from the SDKs you need
  import { initializeApp } from "https://www.gstatic.com/firebasejs/9.8.3/firebase-app.js";
  import { getAnalytics } from "https://www.gstatic.com/firebasejs/9.8.3/firebase-analytics.js";
  // TODO: Add SDKs for Firebase products that you want to use
  // https://firebase.google.com/docs/web/setup#available-libraries
  // Your web app's Firebase configuration
  // For Firebase JS SDK v7.20.0 and later, measurementId is optional
  const firebaseConfig = {
    apiKey: "AIzaSyDd55SAcL-qBGe0iidvrEelD0Lxd2FJbBo",
    authDomain: "myapp-47093.firebaseapp.com",
    projectId: "myapp-47093",
    storageBucket: "myapp-47093.appspot.com",
    messagingSenderId: "202117038660",
    appId: "1:202117038660:web:6fecd6df4a33756b63b211",
    measurementId: "G-D4MXME2D3W"
  };
  // Initialize Firebase
  const app = initializeApp(firebaseConfig);
  const analytics = getAnalytics(app);
</script>
<script src="main.dart.js" type="application/javascript"></script>
</body>
</html>
<body>~</body>に<script type="module">~</script>を追加する
末尾に<script src="main.dart.js" type="application/javascript"></script>を追加する

main.dart

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';

main() {
  Firebase.initializeApp(
    options: const FirebaseOptions(
      apiKey: "AIzaSyDd55SAcL-qBGe0iidvrEelD0Lxd2FJbBo",
      appId: "myapp-47093.firebaseapp.com",
      messagingSenderId: "202117038660",
      projectId: "myapp-47093",
    )
  );
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) => MaterialApp(
        debugShowCheckedModeBanner: false,
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
          visualDensity: VisualDensity.adaptivePlatformDensity,
        ),
        home: const MyFirestorePage(),
      );
}

class MyFirestorePage extends StatefulWidget {
  const MyFirestorePage({Key? key}) : super(key: key);
  @override
  State<StatefulWidget> createState() => _MyFirestorePageState();
}

class _MyFirestorePageState extends State<MyFirestorePage> {
  List<DocumentSnapshot> users = [];
  List<String> nekoItems = [];

  @override
  Widget build(BuildContext context) => Scaffold(
    body: Center(
      child: Column(
        children: <Widget>[
          Container(
            margin: const EdgeInsets.all(8),
            child: ElevatedButton(
              child: const Text('ユーザー neko ushi 登録'),
              onPressed: () {
                  FirebaseFirestore.instance.collection('users').doc(1.toString()).set({'name': 'neko', 'age': 100});
                  FirebaseFirestore.instance.collection('users').doc(2.toString()).set({'name': 'ushi', 'age': 1333});
              },
            )
          ),
          Container(
            margin: const EdgeInsets.all(8),
            child: ElevatedButton(
              child: const Text('item 購入 (neko)'),
              onPressed: () {
                FirebaseFirestore.instance.collection('users').doc(1.toString()).collection('items').doc(1.toString()).set({'name': 'cake', 'price': 600, 'date': '09/13'});
                FirebaseFirestore.instance.collection('users').doc(1.toString()).collection('items').doc(2.toString()).set({'name': 'nasu', 'price': 999, 'date': '12/25'});
              },
            ),
          ),
          Container(
            margin: const EdgeInsets.all(8),
            child: ElevatedButton(
              child: const Text('全ユーザー表示'),
              onPressed: () async { // ユーザーを取得してUIに反映
                final ss = await FirebaseFirestore.instance.collection('users').get();
                setState( (){ users = ss.docs; } );
              },
            ),
          ),
          Column(
            children: [
              for (var e in users) ... {
                Text('${e['name']}さん'), Text('${e['age']}歳'),
              }
            ],
          ),
          ElevatedButton(
            child: const Text('nekoさんの購入物を表示'),
            onPressed: () async { // 購入物を取得してUIに反映
              for (int i = 1; i < 3; i++) {
                final ss = await FirebaseFirestore.instance.collection('users').doc('1').collection('items').doc(i.toString()).get();
                setState( () { nekoItems.add('${ss['name']} ${ss['price']}${ss['date']}'); } );
              }
            },
          ),
          Column(
            children: [
              for (var e in nekoItems) ... { Text(e) }
            ],
          ),
        ],
      ),
    ),
  );
}
エラー "FirebaseOptions cannot be null when creating the default app." の対処
→ Firebase.initializeApp() に初期値を与えることで解決
StatelessWidget に StatefulWidget を載せていくのが定跡らしい
StatelessWidget はインターフェースで Widget build (BuildContext context) => MaterialApp () を定義しなければならない
StatefulWidget はインターフェースで State<StatefulWidget> createState () => nyaa; を定義しなければならない
List<String> nekoItems = []; Dart界隈は変数を lowerCamelCase で書くのが推奨らしい
final ss = await FirebaseFirestore.instance.collection('users').get(); コレクションに対してgetを呼ぶと ss は query snap shot 型になる
setState( (){ users = ss.docs; } ); UIに反映させる変数はsetState内で更新する query snap shot 型はメンバ docs を使うと list<DocumentSnapShot> に変換できる
for (var e in users) ... { Text('${e['name']}さん'), Text('${e['age']}歳'), } children 内で for を使うには ... を書く必要がある
final ss = await FirebaseFirestore.instance.collection('users').doc('1').collection('items').doc(i.toString()).get(); ドキュメントIDを指定してgetを呼ぶと ss は document snap shot 型になる
setState( () { nekoItems.add('${ss['name']} ${ss['price']}円 ${ss['date']}'); } ); document snap shot 型は map 型
欠点: 単純なデザインでもネストが深いのが気になる