- 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 型 欠点 単純なデザインでもネストが深いのが気になる 入力チェックはしてない(これは余裕のあるときに勉強する)