본문 바로가기

웹 개발

[프로젝트] 커서 페이지네이션

백엔드 서버에서 커서 페이지네이션을 구현해서 프론트에서도 페이지네이션 기능을 적용하려고 한다.

class RecordPagination(pagination.CursorPagination):
    page_size = 10
    ordering = "-created_at"
    cursor_query_param = "cursor"

    def get_paginated_response(self, data):
        return Response(
            {
                "meta": {"code": 200, "message": "OK"},
                "data": {
                    "next": self.get_next_link(),
                    "previous": self.get_previous_link(),
                    "records": data,
                },
            },
            status=status.HTTP_200_OK,
        )

DRF에서 제공하는 페이지네이션 기능중에 커서 페이지네이션을 제공하고 있어서

공식 문서에서 찾을 수 있는 내용과 함께 우리 프로젝트에서 사용할 수 있도록 커스텀을 했다.

 

이제 프론트에서 구현해야 하는데 JS를 이용해서 주류 정보를 화면에 표시해주고

화면 하단 근처에 도달했을 때, 주류 정보를 추가적으로 불러오도록 기능을 만드려고 한다.

let nextUrl = 'http://localhost:8000/api/v1/liquor/';
let isLoading = false;

// API에서 주류 정보를 가져오는 함수
async function fetchLiquors(url) {
    try {
        const response = await fetch(url);
        if (!response.ok) {
            throw new Error('Network response was not ok');
        }
        return await response.json();
    } catch (error) {
        console.error('Error fetching liquors:', error);
    }
}

// 주류 정보를 화면에 표시하는 함수
function displayLiquors(liquors) {
    const liquorList = document.getElementById('liquor-list');
    liquors.forEach(liquor => {
        const liquorItem = document.createElement('div');
        liquorItem.className = 'liquor-item';
        liquorItem.innerHTML = `
            <img src="${liquor.img}" alt="${liquor.name}" class="liquor-img" data-id="${liquor.id}">
            <h3>${liquor.name}</h3>
            <p>Price: ${liquor.price} 원</p>
        `;
        liquorList.appendChild(liquorItem);
    });


    document.querySelectorAll('.liquor-img').forEach(img => {
        img.addEventListener('click', function () {
            const liquorId = this.getAttribute('data-id');
            window.location.href = `/pages/liquor_detail.html?id=${liquorId}`; // 상세 페이지로 이동
        });
    });
}

// 더 많은 주류 데이터를 로드하는 함수
async function loadMoreLiquors() {
    if (isLoading || !nextUrl) return;

    isLoading = true;
    document.getElementById('loading').style.display = 'block';

    const data = await fetchLiquors(nextUrl);
    if (data) {
        displayLiquors(data.data.records);
        nextUrl = data.data.next; // 다음 페이지 URL 업데이트
        isLoading = false;
        document.getElementById('loading').style.display = 'none';
    }
}

// 화면 하단 근처에 도달했는지 체크하는 함수
function isNearBottom() {
    return window.innerHeight + window.scrollY >= document.body.offsetHeight - 300;
}

// 스크롤 이벤트 핸들러
function handleScroll() {
    if (isNearBottom()) {
        loadMoreLiquors();
    }
}

// 초기 주류 데이터를 로드
loadMoreLiquors();

// 스크롤 이벤트 추가
window.addEventListener('scroll', handleScroll);

위의 코드는 주류 정보를 가져와서 주류 정보를 화면에 표시하고

남은 화면이 300px 이하가 되면 새로운 데이터를 로드해서 스크롤 길이가 늘어난다.

프론트에서는 코드를 적용하기 어려워서 헤메는 일이 많지만 최대한 백엔드에서 보내는 데이터 형식을 보고

거기에 맞춰서 데이터를 보여줄 수 있도록 기능을 잘 만들어야겠다.