7K12 blog

猫でも分かる何か

web54最新 Cloud Firestore

  • project url

https://github.com/tkr987/web54

  • 参考

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> {
  String age = '';
  String uid = '';
  String item = '';
  String name = '';
  String price = '';
  List<DocumentSnapshot> users = [];
  List<String> items = [];

  @override
  Widget build(BuildContext context) => Scaffold(
    body: Center(
      child: Column(
        children: <Widget>[
          TextField(
            decoration: const InputDecoration(hintText: '名前'),
            onChanged: (text) { name = text; },
          ),
          TextField(
            decoration: const InputDecoration(hintText: '年齢'),
            onChanged: (text) { age = text; },
          ),
          Container(
            margin: const EdgeInsets.all(8),
            child: ElevatedButton(
              child: const Text('ユーザー 登録'),
              onPressed: () async {
                final ss = await FirebaseFirestore.instance.collection('users').get();
                int n = ss.docs.length + 1;
                FirebaseFirestore.instance.collection('users').doc(n.toString()).set({'name': name, 'age': age});
              },
            )
          ),
          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 i = 0; i < users.length; i++) ... {
                Text('user_id = $i ${users[i]['name']}さん ${users[i]['age']}歳'),
              }
            ],
          ),
          TextField(
            decoration: const InputDecoration(hintText: 'user id'),
            onChanged: (text) { uid = text; },
          ),
          TextField(
            decoration: const InputDecoration(hintText: '商品名'),
            onChanged: (text) { item = text; },
          ),
          TextField(
            decoration: const InputDecoration(hintText: '値段'),
            onChanged: (text) { price = text; },
          ),
          Container(
            margin: const EdgeInsets.all(8),
            child: ElevatedButton(
              child: const Text('商品購入'),
              onPressed: () async {
                final ss = await FirebaseFirestore.instance.collection('users').doc(uid.toString()).collection('items').get();
                int n = ss.docs.length + 1;
                FirebaseFirestore.instance.collection('users').doc(uid.toString()).collection('items').doc(n.toString()).set({'name': item, 'price': price});
              },
            ),
          ),
          TextField(
            decoration: const InputDecoration(hintText: 'user id'),
            onChanged: (text) { uid = text; },
          ),
          ElevatedButton(
            child: const Text('購入物を表示'),
            onPressed: () async { // 購入物を取得してUIに反映
              final ss = await FirebaseFirestore.instance.collection('users').doc(uid).collection('items').get();
              for (var e in ss.docs) {
                setState( () { items.add('${e['name']} ${e['price']}円'); } );
              }
            },
          ),
          Column(
            children: [
              for (var e in items) ... { 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 を使うには ... を書く必要がある
setState( () { items.add('${e['name']} ${e['price']}円'); } ); document snap shot 型は map 型
欠点
単純なデザインでもネストが深いのが気になる
入力チェックはしてない(これは余裕のあるときに勉強する)