0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

今週は不具合の週でした。。。
ストレージやコードが正しいのに反映されない?現象が起こってましたが
なんとか解決できましたので
引き続き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の記載

・データを一冊分追加

provider①.png

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に追加する

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を作成
provider②.png
※現状のイメージ画像

・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をインポート
・データを返す準備処理を記載

book_list_model.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を作成
provider③.png

※現状のイメージ画像

・book.dartにBook classを作成しtitleとauthorを定義する

book.dart
class Book {
  Book(this.title, this.author);
  String title;
  String author;
}

・book_list_model_dartのfetchBookList関数の中にBookへ変換するための値を入れる
・booksへの代入処理を行う
・Bookリストのインスタンスが生成された際にfetchBookListメソッドを呼び出すように処理
・UIやWidgetに通知する処理を記載

book_list_model.dart
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中となる)を記載

book_list_page.dart
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」をクリック
firebase_add⑨.png
・「ドキュメントを追加」をクリック
・ドキュメントIDの「自動ID」をクリック
・フィールドに「title」、値に「エコノミー革命」を入力
・フィールドの追加→フィールドに「サクッとわかる ビジネス教養 行動経済学」、
 値に「阿部 誠」を入力
・保存をクリック
firebase_add⑨.png

7.全体コード

book_list_page.dart
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),
        ),
      ),
    );
  }
}
book_list_model.dart
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();
    });
  }
}
book.dart
class Book {
  Book(this.title, this.author);
  String title;
  String author;
}

pubspec.yamlは変更点のあった35~40行目付近のみを記載

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

参考文献

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を数回更新すると解決しました笑
・皆さんも定期的な更新を心がけてください!

  1. 親Widgetから子Widgetにデータを受け渡すことが出来る処理のこと

  2. ChangeNotifier のインスタンス(モデル)をその子孫に提供するウィジェット

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?