今週は不具合の週でした。。。
ストレージやコードが正しいのに反映されない?現象が起こってましたが
なんとか解決できましたので
引き続きFlutter関連の投稿を進めようと思います!!
備忘録として使用する予定ですが
皆さんの解決策にもなれば幸いです。
今回はFirebaseのproviderをインストールしてPageとModelに分割します。
目次
-完成イメージ
-1.構成
-2.Providerを使用してPageとModelに分割①_Providerをインストール
-3.Providerを使用してPageとModelに分割②_ディレクトリの整理
-4.Providerを使用してPageとModelに分割③_Bookクラスの作成
-5.Providerを使用してPageとModelに分割④_ChangeNotifierProviderを記載
-6.Providerを使用してPageとModelに分割⑤_データの追加
-7.全体コード
-参考文献
-最後に
完成イメージ
・前回の記事からFlutterアプリにProvider1を追加
※下記前回記事
・ディレクトリの整理
・Modelの作成
・bookクラスの作成
・ChangeNotifierProvider2の記載
・データを一冊分追加

1.構成
・Providerをpubspec.yamlに追加
・libフォルダ内でbook_listフォルダを作成
・book_listフォルダにbook_list_page.dartを移動し
book_list_model.dartを作成する
・libフォルダ内でdomainフォルダを作成
・domainフォルダにbook.dartを作成
・book_list_page.dartにChangeNotifierProviderを記載
・Firebaseサイトより一冊分データを追加
2.Providerを使用してPageとModelに分割①_Providerをインストール
・下記を参考に最新のProviderをpubspec.yamlに追加する
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.6
firebase_core: ^3.1.0
cloud_firestore: ^5.0.1
provider: ^6.1.2//←こちらを追加
3.Providerを使用してPageとModelに分割②_ディレクトリの整理
・libフォルダにbook_listフォルダを作成
・book_listフォルダにbook_list_page.dartを移動
・book_listフォルダにbook_list_model.dartを作成
※現状のイメージ画像
・book_list_model.dartにBookListModel class作成
・fetchBookList関数を作成
・book_list_page.dartからfinal Stream 〜を切り取りし
book_list_model.dartに貼り付け
・book_list_page.dartからsnapshot.data!docs.map〜をコピーして
book_list_model.dartに貼り付け。少し加工
・firestoreをインポート
・material.dartをインポート
・データを返す準備処理を記載
import 'package:cloud_firestore/cloud_firestore.dart';//←firestoreをインポート
import 'package:flutter/material.dart';//←material.dartをインポート
class BookListModel extends ChangeNotifier {
final Stream<QuerySnapshot> _usersStream =
FirebaseFirestore.instance.collection('books').snapshots();//final Stream<QuerySnapshot> 〜をbook_list_page.dartから切り取りし貼り付け
void fetchBookList() {//←fetchBookList関数を作成
_usersStream.listen((QuerySnapshot snapshot) {
final List<Book> books = snapshot.docs.map((DocumentSnapshot document) {//←snapshot.data!docs.map〜をbook_list_page.dartからコピーし貼り付け。少し加工。
Map<String, dynamic> data = document.data()! as Map<String, dynamic>;//データを返す準備処理を記載
}).toList();
});
}
}
4.Providerを使用してPageとModelに分割③_Bookクラスの作成
・libフォルダにdomainフォルダを作成
・book_listフォルダにbook.dartを作成
※現状のイメージ画像
・book.dartにBook classを作成しtitleとauthorを定義する
class Book {
Book(this.title, this.author);
String title;
String author;
}
・book_list_model_dartのfetchBookList関数の中にBookへ変換するための値を入れる
・booksへの代入処理を行う
・Bookリストのインスタンスが生成された際にfetchBookListメソッドを呼び出すように処理
・UIやWidgetに通知する処理を記載
List<Book>? books;//←booksへの代入処理
BookListModel() {//Bookリストのインスタンスが生成された際にfetchBookListメソッドを呼び出すように処理
fetchBookList();
}
void fetchBookList() {
_usersStream.listen((QuerySnapshot snapshot) {
final List<Book> books = snapshot.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data = document.data()! as Map<String, dynamic>;
final String title = data['title'];//←Bookへ変換するための値
final String author = data['author'];//←Bookへ変換するための値
return Book(title, author);//←Bookへ変換するための値
}).toList();
this.books = books;//←booksへの代入処理
notifyListeners();//←UIやWidgetに通知する処理
});
}
※fetchbooklist関数の処理前はListの中身はnullとなるためnull許容の?を入れて
List< Book >? books;としている
5.Providerを使用してPageとModelに分割④_ChangeNotifierProviderを記載
・book_list_page.dartでCenter Widget内のStreamBuilderから全て削除
・下記を参考にConsumer〜をCenter Widgetに代入
・providerをインポート
・下記記事を参考にScaffoldにWidgetを囲みChangeNotifierProviderを代入
・CountModelをBookListModelへ変更
・booksを定義しListviewで返すためにWidgetへ変換する
※ListViewはWidgetで返せるので変換が必要
・bookがnullの場合の処理(Loading中となる)を記載
import 'package:firebase1_firebase_add/book_list/book_list_model.dart';
import 'package:firebase1_firebase_add/domain/book.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';//←providerをインポート
class BookListPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<BookListModel>(//←Widgetで囲み、ChangeNotifierProviderを代入・CountModelをBookListModelへ変更
create: (_) => BookListModel(),//←CountModelをBookListModelへ変更
child: Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text('本一覧'),
),
body: Center(//CenterWidget内を削除し添付記事からConsumer~を代入
child: Consumer<BookListModel>(builder: (context, model, child) {//←CountModelをBookListModelへ変更
final List<Book>? books = model.books;//←booksを定義
if (books == null) {//←bookがnullの場合の処理(Loading中となる)を記載
return CircularProgressIndicator();
}
final List<Widget> widgets = books//←booksをWidgetに変換
.map(
(book) => ListTile(
title: Text(book.title),
subtitle: Text(book.author),
),//←booksをWidgetに変換
)
.toList();
return ListView(//←widgets(books)をListviewに返すように処理
children: widgets,
);
}),
),
floatingActionButton: FloatingActionButton(
onPressed: null,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
),
);
}
}
6.Providerを使用してPageとModelに分割⑤_データの追加
・下記リンクにログインする
※ログインは先ほどログインしたものと同様のアカウント
https://firebase.google.com/
・右上の「Go to Console」をクリック
・作成したプロジェクトをクリック
・左のタブの「構築」→「Firestore Database」をクリック
・「ドキュメントを追加」をクリック
・ドキュメントIDの「自動ID」をクリック
・フィールドに「title」、値に「エコノミー革命」を入力
・フィールドの追加→フィールドに「サクッとわかる ビジネス教養 行動経済学」、
値に「阿部 誠」を入力
・保存をクリック
7.全体コード
import 'package:firebase1_firebase_add/book_list/book_list_model.dart';
import 'package:firebase1_firebase_add/domain/book.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class BookListPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<BookListModel>(
create: (_) => BookListModel(),
child: Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text('本一覧'),
),
body: Center(
child: Consumer<BookListModel>(builder: (context, model, child) {
final List<Book>? books = model.books;
if (books == null) {
return CircularProgressIndicator();
}
final List<Widget> widgets = books
.map(
(book) => ListTile(
title: Text(book.title),
subtitle: Text(book.author),
),
)
.toList();
return ListView(
children: widgets,
);
}),
),
floatingActionButton: FloatingActionButton(
onPressed: null,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
),
);
}
}
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase1_firebase_add/domain/book.dart';
import 'package:flutter/material.dart';
class BookListModel extends ChangeNotifier {
final Stream<QuerySnapshot> _usersStream =
FirebaseFirestore.instance.collection('books').snapshots();
List<Book>? books;
BookListModel() {
fetchBookList();
}
void fetchBookList() {
_usersStream.listen((QuerySnapshot snapshot) {
final List<Book> books = snapshot.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data = document.data()! as Map<String, dynamic>;
final String title = data['title'];
final String author = data['author'];
return Book(title, author);
}).toList();
this.books = books;
notifyListeners();
});
}
}
class Book {
Book(this.title, this.author);
String title;
String author;
}
pubspec.yamlは変更点のあった35~40行目付近のみを記載
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.6
firebase_core: ^3.1.0
cloud_firestore: ^5.0.1
provider: ^6.1.2
参考文献
Flutter大学. 「【2021年8月最新】Providerを使って画面をPageとModelに分割しよう」. YouTube. 2021/08,https://www.youtube.com/watch?v=MvNyZrMr-3c&list=PLuLRJz1UnJzEYLFd1ihJit1E6dYol8VC5&index=3&t=0, (参照 2024-07-08)
pub.dev. 「provider 6.1.2」. provider| Flutter packege.
https://pub.dev/packages/provider, (参照 2024-07-08)
flutteruniv. 「flutter_provider_samples」. Github.
https://github.com/flutteruniv/flutter_provider_samples/blob/master/lib/count_page.dart, (参照 2024-07-08)
最後に
・今回こちらを作成しビルドするとbooksがnullとなり
画面がLoading中となっておりました。
・動画を5回程見返しましたがコード自体に誤りはなく路頭に迷っていましたが
VScodeを数回更新すると解決しました笑
・皆さんも定期的な更新を心がけてください!