[Flutter] Pagination

향신료·2023년 8월 9일
0

Pagination?

대량의 데이터를 페이지 단위로 나누어 표시하는 기술.




특징


데이터의 페이지 단위 나눔

대량의 데이터를 작은 페이지로 나누어서 사용자에게 보여주므로 한 번에 모든 데이터를 로드하지 않아

성능을 향상시키고 메모리 사용량을 줄일 수 있습니다.


서버 요청 최적화

필요한 만큼의 데이터를 서버에서 요청하므로 네트워크 트래픽을 최적화할 수 있습니다.


데이터 처리 용이성

작은 페이지 단위로 나누어 사용하므로 데이터를 처리하기가 더 편리해집니다.

ex ) 특정 페이지만 새로고침하는 경우 해당 페이지만 데이터 수정 및 업데이트를 진행.





주의점


빠른 스크롤 시 누락 및 중복 데이터 발생

사용자가 빠르게 스크롤할 경우, 중간에 데이터의 누락 및 중복이 발생하거나 급속도로 연속적인 서버 호출이 발생할 수 있습니다.


데이터 일관성 문제

각 페이지가 시간에 따라 변경될 수 있으므로, 사용자에게 일관된 데이터를 제공하기 위해 적절한 캐싱이나 관리가 필요합니다.





⚠️ 위와 같은 주의점이 있으므로 필요에 따라 최적화가 필요합니다!







구현 예시

구현하는 방법에는 여러 가지가 있지만 그 중 아래에서 구현할 방법은 가장 일반적인 방법인 ListView.builder 와 GridView.builder 중 본 예시에서는 ListView를 이용해 진행합니다.



구현 코드

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Pagination 예시'),
        ),
        body: PaginationTest(),
      ),
    );
  }
}

class PaginationTest extends StatefulWidget {
  
  _PaginationTestState createState() => _PaginationTestState();
}

class _PaginationTestState extends State<PaginationTest> {
  List<String> items = List.generate(15, (index) => '${index + 1}번째 위젯');
  final ScrollController _scrollController = ScrollController();
  bool isLoading = false; // 다중 로드를 막기 위한 변수

  
  void initState() {
    super.initState();
    _scrollController.addListener(_onScroll);
  }

  
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return ListView.builder(
      controller: _scrollController,
      itemCount: items.length + 1, // 로딩 인디게이터 표시를 위한 추가
      itemBuilder: (context, index) {
        if (index < items.length) {
          return ListTile(
            title: Text(items[index]),
          );
        } else {
          return isLoading
              ? const CircularProgressIndicator()
              : const SizedBox();
        }
      },
    );
  }

  void _onScroll() {
    if (_scrollController.position.pixels ==
        _scrollController.position.maxScrollExtent) {
      // 최대 스크롤까지 도달 시 새로운 데이터 로드
      _loadData();
    }
  }

  Future<void> _loadData() async {
    if (!isLoading) {
      setState(() {
        isLoading = true;
      });

			await Future.delayed(Duration(seconds: 4)); // 로딩 인디게이터 표시를 위한 딜레이
      
      List<String> newItems = List.generate(
          10, (index) => '새로 추가 된 ${items.length + index + 1}번째 위젯');

      setState(() {
        items.addAll(newItems);
        isLoading = false;
      });
    }
  }
}

추가 설명

스크롤이 끝에 도달할 때마다 _loadData 함수를 호출하여 새로운 데이터를 추가합니다.

isLoading 변수를 이용해 데이터를 가져오는 중이라면 로딩 인디케이터 표시와 함께 중복 호출을 방지합니다.

profile
드문드문 기초 정보를 올리는 블로그

2개의 댓글

comment-user-thumbnail
2023년 8월 9일

개발자로서 배울 점이 많은 글이었습니다. 감사합니다.

1개의 답글