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/Bloc/Firestoreを用いた開発プロセス

Last updated at Posted at 2025-03-26

はじめに

私がアプリを個人開発する中で、どのような順番で実装を進めているか備忘録的な意味を込めて残しておこうと思います。

開発環境

言語:Dart
フレームワーク:Flutter
アーキテクチャ:Bloc
DB:Firestore

ディレクトリ構成

下記はlib配下のディレクトリ構成です。
主要なディレクトリを抜き出しています。

.
├── blocs
│   ├── hoge_bloc.dart
├── main.dart
├── models
│   ├── hoge_model.dart
├── repositories
│   ├── hoge_repository.dart
└── screens
    └── hoge_screen.dart

開発プロセス

1: DB設計を行う
まずはDBにどのようなデータを保存するか設計します。
イメージしたDBを元にFirestoreにコレクションとドキュメントのダミーデータを入れておきます。

2: modelの作成
設計を元にmodelを作成します。

hoge_model.dart
class HogeModel {
  HogeModel({
    required this.fuga,
  });
  
  final int fuga;

  factory HogeModel.fromDocument(DocumentSnapshot<Object?> doc) {
    final Map<String, dynamic> data = doc.data() as Map<String, dynamic>;
    return HogeModel(
      fuga: data['fuga'],
    );
  }

  Map<String, dynamic> toMap() {
    return <String, dynamic>{
      'fuga': fuga,
    };
  }
}

3: repositoryの作成
firestore↔BlocをつなぐためのAPIを作成します。
API作成時点でfirestoreとの接続確認を行っておくと良いと思います。

hoge_repository.dart
class HogeRepository {
  final FirebaseFirestore _firestore = FirebaseFirestore.instance;

  Future<void> addFuga(String fuga) async {
    await _firestore.collection('fugaCollection').add(fuga.toMap());
  }

  Future<String?> fetchFuga() async {
    final fugaDoc = await _firestore.collection('fugaCollection').doc('fugaDoc').get();
    if (fugaDoc.exists) {
      return HogeModel.fromDocument(fugaDoc);
    }
    return null;
  }
}

4: blocの作成
Bloc↔screenをつなぐためのBlocを作成します。

hoge_bloc.dart
class HogeBloc extends Bloc<HogeEvent, HogeState> {
  HogeBloc() : super(HogeState()) {
    on<HogeEventFuga>((
      HogeEventFuga event,
      Emitter<HogeState> emit,
    ) async {
      _hogeRepository.addFuga(
        event.fuga,
      );
    });
  }

  final HogeRepository _hogeRepository = HogeRepository();
}

5: screenの作成
画面を作成します。

hoge_screen.dart
class HogePage extends StatelessWidget {
  const HogePage({super.key});

  @override
  Widget build(BuildContext context) {
    return BlocProvider<HogeBloc>(
      create: (BuildContext context) => HogeBloc(),
      child: const HogeScreen(),
    );
  }
}

class HogeScreen extends StatelessWidget {
  const HogeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(
          'Hoge Screen',
        ),
      ),
      body: BlocBuilder<HogeBloc, HogeState>(
        builder: (BuildContext context, HogeState state) {
          return TextButton(
            child: const Text('button'),
            onPressed: () {
              context
                  .read<HogeBloc>()
                  .add(HogeEventFuga('piyo'));
            },
          );
        },
      ),
    );  
  }
}

最後に

私が紹介したのはデータの依存関係にしたがって依存元から実装していくやり方です。
序盤の設計やイメージが問題なければ、無駄な作業なく効率よく開発できます。
逆にUIから実装していくパターンは、直感的に実装できるのと、後続のフェーズは前段のフェーズの依存を解決する方向で進めるため、手戻りが少ない印象です。
しかしダミーで実装しなければならない部分もあるため、その工数がネックというところかなと思っています。
参考になる部分があれば幸いです。

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?