🪁
Supabaseのテーブルを2個表示したい。
💡Tips
Supabaseからテーブルの情報を2個取得して、画面に表示したいが、joinして、freezed使うのが無理そうだから、whenをネストして、RiverpodのStreamProviderを使ったらデータ取れた。
この記事の対象者
- Supabaseの経験がある人
- riverpod + freezedの経験がある人
とりあえずやってみた。
メモ書きのようなモンなので、コード全部載せてないです🙇
実は仕事で書いてる実験用のコードです。いいもんではないかも???
モデルを作る
モデル
// user用
class TUserState with _$TUserState {
const factory TUserState({
(0) int id,
('') String uuid,
('') String birthday,
('') String job_id,
('') String iconImagePath,
('') String user_name,
('') String profile,
DateTime? created_at,
DateTime? updated_at,
(false) bool is_delete,
}) = _TUserState;
factory TUserState.fromJson(Map<String, dynamic> json) =>
_$TUserStateFromJson(json);
}
// task用
class TTaskState with _$TTaskState {
const factory TTaskState({
(0) int id,
('') String status,
('') String task_name,
DateTime? created_at,
DateTime? updated_at,
(false) bool is_delete,
(0) int goal_id,
(0) int user_id,
}) = _TTaskState;
factory TTaskState.fromJson(Map<String, dynamic> json) =>
_$TTaskStateFromJson(json);
}
プロバイダーを作る。joinするクエリがあるのだ、freezedをネストさせて、tasksというプロパティからアクセするのが、できなかった???
for文で、ループすればデータ取れると思ったがうまくいかなかった....
StreamProviderを使ってみた
// user用
Stream<List<TUserState>> tUserList(TUserListRef ref) {
final supabase = Supabase.instance.client;
return supabase.from('t_user').stream(primaryKey: ['id']).limit(5).map(
(event) => event.map(TUserState.fromJson).toList(),
);
}
// task用
Stream<List<TTaskState>> tTaskList(TTaskListRef ref) {
final supabase = Supabase.instance.client;
return supabase.from('t_task').stream(primaryKey: ['id']).limit(5).map(
(event) => event.map(TTaskState.fromJson).toList(),
);
}
View側には、whenをネストして、Listの文法で、minと呼ばれるメソッドがあり、これを使わないとどちらか一方のListの数にあわせて、データを取得ができないので必要だった💦
whenをネストしてみた
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import '../../core/theme/app_color.dart';
import '../../infrastructure/supabase_provider/t_task_provider.dart';
import '../../infrastructure/supabase_provider/t_user_provider.dart';
enum Selected { edit, delete }
class FeedPage extends HookConsumerWidget {
const FeedPage({super.key});
Widget build(BuildContext context, WidgetRef ref) {
final selectedMenu = useState<Selected>(Selected.edit);
final tUser = ref.watch(tUserListProvider);
final tTask = ref.watch(tTaskListProvider);
return Scaffold(
appBar: AppBar(),
backgroundColor: AppColor.grey,
floatingActionButton: FloatingActionButton(
onPressed: () async {},
child: const Icon(Icons.add),
),
// tUserとtTaskをwhenでネストさせて表示。lengthはminを使う
body: tUser.when(
data: (tUser) => tTask.when(
data: (tTask) => ListView.builder(
itemCount: min(tUser.length, tTask.length),
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.blue,
radius: 20,
backgroundImage: NetworkImage(tUser[index].iconImagePath),
),
title: Text(tUser[index].user_name),
subtitle: Text(tTask[index].task_name),
trailing: PopupMenuButton<Selected>(
onSelected: (result) {
selectedMenu.value = result;
},
itemBuilder: (context) => <PopupMenuEntry<Selected>>[
const PopupMenuItem<Selected>(
value: Selected.edit,
child: Text('Edit'),
),
const PopupMenuItem<Selected>(
value: Selected.delete,
child: Text('Delete'),
),
],
),
),
);
},
),
loading: () => const CircularProgressIndicator(),
error: (error, stackTrace) => Text('Error: $error'),
),
loading: () => const CircularProgressIndicator(),
error: (error, stackTrace) => Text('Error: $error'),
),
);
}
}
データの取得に成功すると、View側に二つのテーブルの情報を表示することができた。世の中のSNSはREST APIなのだろうけど...
まとめ
Firestoreでもwhenをネストさせたことがあるが、あっちよりは簡単な気がしたが、いけてるコードではない気がします。他に良い方法があればいいんですけどね〜
joinして、View側に表示できないものか...
Discussion