はじめに
Flutterでのアプリ開発では、バックエンドのAPIが完成する前にフロントエンドのUIを先に進めたい場合がよくある。この記事では、サーバー側のAPIが実装されていない間に、Flutterアプリでダミーデータを使って開発を進める方法を記載。
関連記事はこちら
JSONダミーデータをfakesクラスで用意
まず、Freezedアノテーションを使用してUser
クラスを定義し、JSONからデータを生成するためのコードをFreezedで生成する。
このコードは、freezed
パッケージによって生成されたコードを含む。そのため、flutter pub run build_runner build
コマンドを実行して、関連するファイルを生成する必要がある。
import 'package:freezed_annotation/freezed_annotation.dart';
part 'user.freezed.dart';
part 'user.g.dart';
@freezed
class User with _$User {
const factory User({
required String id,
required String name,
required String email,
}) = _User;
factory User.fromJson(Map<String, dynamic> json) =>
_$UserFromJson(json);
}
次に、実際のAPIレスポンスを模倣したJSONダミーデータをfakes
クラスで用意。
Fakes
クラスは、Flutterで使用されるダミーデータを生成するためのユーティリティクラス。
Fakeクラスに関する公式ドキュメントはこちら。
https://api.flutter.dev/flutter/test_api.fake/Fake-class.html
fakes
クラスを使用するためにインストールは必要ない。fakes
クラスは、下記のようにプロジェクト内に自分で定義して、その中に静的なダミーデータリストを用意する。
import 'user.dart'; // Userクラスを定義したファイルをインポート
class Fakes {
static final List<User> users = [
{
"id": "1",
"name": "山田太郎",
"email": "taro@example.com",
},
{
"id": "2",
"name": "佐藤花子",
"email": "hanako@example.com",
},
// 他のダミーユーザーのデータを追加...
];
}
FakeUserRepositoryクラスの作成(APIリクエストの模倣)
ダミーデータを管理し、APIリクエストを模倣するメソッドfetchUsers
を提供する。
将来的にはバックエンドからのデータ取得に置き換えるが、この時点では、Fakes.users
リストから即座にダミーデータを返している。
class FakeUserRepository {
// User オブジェクトのリストを返す偽のAPI関数(fetchUsers())を作成
Future<List<User>> fetchUsers() async {
// Fakesクラスで作成したusersリストが返ってくる。
return Future.value(Fakes.users);
}
}
UIにデータ表示
Userオブジェクトを表示するウィジェットを作成する。HooksConsumerWidget
を使用して、Riverpod のプロバイダーからデータを取得する。取得したUser
リストをリストビューとして表示する。
usersProvider
: ダミーデータのUser
オブジェクトのリストを提供するRiverpodのプロバイダーです。Fakes.users
を直接返している。UsersView
:HookConsumerWidget
を継承したウィジェットで、usersProvider
からデータを受け取り、UIに表示する。Scaffold
ウィジェット内でListView.builder
を使用して、取得したUser
オブジェクトのリストをリストビューとして表示。
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'your_project_path/models/user.dart'; // 実際のファイルパスに置き換えてください
import 'your_project_path/fakes/fakes.dart'; // Fakesクラスの実際のパスに置き換えてください
final usersProvider = Provider<List<User>>((ref) {
return Fakes.users; // ダミーデータを提供
});
class UsersView extends HookConsumerWidget {
const UsersView({Key? key}) : super(key: key); // コンストラクタにkeyを追加
@override
Widget build(BuildContext context, WidgetRef ref) {
final users = ref.watch(usersProvider); // usersProviderからユーザーデータを取得
return Scaffold(
appBar: AppBar(
title: const Text('ユーザー一覧'),
),
body: users.isNotEmpty
? ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
final user = users[index];
return ListTile(
title: Text(user.name),
subtitle: Text(user.email),
onTap: () {
// 詳細画面への遷移処理を追加(必要なら)
},
);
},
)
: const Center(child: Text('データがありません')), // データが空の場合は中央にテキストを表示
);
}
}
API実装されたら、リアルタイムのデータに切り替えて検証
サーバーのAPIが完成するまでの間、この方法でUIの開発を進めることができる。APIが実装されたら、リアルタイムのデータに切り替える。
例が、userデータではなく、drug_recordデータ
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:phr_app_expo/common/fakes/fakes.dart';
import 'package:phr_app_expo/data/clients/api_client.dart';
import 'package:phr_app_expo/data/clients/api_path.dart';
import 'package:phr_app_expo/data/clients/base_client.dart';
import 'package:phr_app_expo/data/entities/recoell/drug_record.dart';
import 'package:phr_app_expo/data/responses/drug_records_response.dart';
final drugRecordsRepositoryProvider = Provider<DrugRecordsRepository>((ref) {
return DrugRecordsRepositoryImpl(ref.read(apiClientProvider));
// 実際のリポジトリの代わりに、偽のリポジトリを使用する
// return FakeDrugRecordsRepositoryImpl();
});
abstract class DrugRecordsRepository {
Future<List<DrugRecord>> getDrugRecords();
}
class DrugRecordsRepositoryImpl extends DrugRecordsRepository {
DrugRecordsRepositoryImpl(this._apiClient);
final BaseClient _apiClient;
@override
Future<List<DrugRecord>> getDrugRecords() async {
final response = await _apiClient.get(
ApiPath.recoellDrugRecords,
) as Map<String, dynamic>;
return DrugRecordsResponse.fromJson(response).drugRecords;
}
}
class FakeDrugRecordsRepositoryImpl extends DrugRecordsRepository {
FakeDrugRecordsRepositoryImpl();
@override
Future<List<DrugRecord>> getDrugRecords() async {
return Fakes.drugRecords;
}
}
APIリクエストとresponseの処理が無事できていれば、一発成功で表示されるはず!
無事表示された!
コメント