🙆

[Flutter Web × Supabase] Pagination の実装をしてみた

2023/12/04に公開

Flutter大学 Advent Calendar 2023 4日目 です。

個人開発で Pagination を実装する機会があったので記事にしていきます。

いきなりですが皆さん Pagination の読み方を知っていますか? 私はつい、最近までページネーションと読んでいましたが本来の読み方は パジネーション(パージネーション)です。
https://qiita.com/yd_niku/items/e81fabff27971a4e2226

話が逸れたので本題に戻ります。

本記事について

以下のスクショにあるように Flutter で Pagination を実装についてまとめています。

https://pub.dev/packages/flutter_web_pagination

Pagination の Widget で以下のパッケージが使いやすかったのでこれを使っていきます。
https://pub.dev/packages/flutter_web_pagination

Supabase を用いて Flutter Web で Pagination の実装について紹介します。また、状態管理は Riverpod を使用します。

本記事は heyhey さんの 記事を活用させてもらっています。そのため、Supabase の基本的な部分は省略しています。
https://zenn.dev/flutteruniv_dev/articles/crud_with_supabase

環境

バージョン
Flutter 3.13.7
dart 3.1.3

使用パッケージ

pubspec.ymal
dependencies:
  flutter_web_pagination: ^0.0.3
  supabase_flutter: ^1.10.25
  flutter_riverpod: ^2.4.9

実装

サンプルプロジェクトです。
https://github.com/fen0268/Sample-Pagination

ディレクトリ構造
lib/
   ├ controller/
   │      ├ current_page_controller.dart
   │      └ people_controller.dart 
   ├ model/
   │      └ people.dart
   ├ page/
   │      └ home_page.dart
   ├ widget/
   │      ├ custom_list_tile_widget.dart
   │      └ pagination_widget.dart
   └ main.dart

テストデータを作成

以下のサイトで CSV のデータを作成します。出力行数は100以上あればいいと思います。
https://tm-webtools.com/Tools/TestData

Supabase の Table Editor の画面中央にある Create a new table をクリックし、右下あたりに Import data via spreadsheet があるのでクリックすると、CSV のファイルをアップロードできる画面が開くので先程、作成した CSV ファイルをアップロードします。

コピペで動く Pagination 一部紹介

current_page_controller.dart
/// 現在のページ数を管理する
class CurrentPageNotifier extends AutoDisposeNotifier<int> {
  
  int build() {
    // ページ数を返す
    // 初期値は 1 ページ目のため 1 を返す
    return 1;
  }
  
  /// ボタンが押されたタイミングで更新をかける
  void changePage(int value) {
    state = value;
  }
}
people_controller.dart
/// 全件取得する
/// Pagination を表示する際にボタンの数は総データ数にされるので把握しておかなといけない
final fetchAllPeopleProvider = StreamProvider.autoDispose<List<People>>(
  (ref) async* {
    final data = await client
        .from('people')
        .select<PostgrestList>('family, name')
        .order('id', ascending: false);
    yield data.map(People.fromJson).toList();
  },
);


/// currentPageNotifierProvider の値に応じて、データを取得する 
final fetchPerPagePeopleProvider = StreamProvider.autoDispose<List<People>>(
  (ref) async* {
    final currentPage = ref.watch(currentPageNotifierProvider);

    final data = await client
        .from('people')
        .select<PostgrestList>('family, name')
        .order('id', ascending: false)

        // 本サンプルでは 1 ページあたり 10 件表示する
        .range(currentPage * 10 - 10, currentPage * 10 - 1)
        .limit(10);
    yield data.map(People.fromJson).toList();
  },
);

people_controller.dart

class PaginationWidget extends ConsumerWidget {
  const PaginationWidget({super.key});

  
  Widget build(BuildContext context, WidgetRef ref) {
    /// 現在のページ数を取得
    final currentPage = ref.watch(currentPageNotifierProvider);

    /// 総件数を取得
    final data = ref.watch(fetchAllPeopleProvider).value?.length;

    /// 1 ページあたりの表示件数
    const itemsPerPage = 10;

    // 総件数が 0 または null の場合は Pagination を表示しない
    if (data == null || data == 0) {
      return const SizedBox();
    }

    return WebPagination(
      // ボタンが押されたタイミングでの処理
      onPageChanged: (page) {
        ref.read(currentPageNotifierProvider.notifier).changePage(page);
      },

      // 現在のページ数
      currentPage: currentPage,

      // 総ページ数
      // currentPage が 1 から始まるため、1 を足す
      // (data - 1) は data が [itemsPerPage] の値の倍数のとき、
      // -1 をしないと総ページ数が 1 増えてしまうため、-1 をする
      totalPage: (data - 1) ~/ itemsPerPage + 1,

      // 表示するボタン数
      displayItemCount: 7,
    );
  }
}

まとめ

本記事では、Supabase を用いてFlutter Web で Pagination の実装について紹介しました。flutter_web_paginationパッケージを使用し、サンプルプロジェクトを通じて具体的なコードを示しました。

この記事が Flutter Web での Paginationの実装についての理解を深める一助となれば幸いです。
ありがとうございました!

https://flutteruniv.com/
https://twitter.com/fencer0268

Flutter大学

Discussion