무한 스크롤 그거 그렇게 구현하는거 아닌데

이호영·2022년 4월 3일
86
post-thumbnail

직설적인 제목으로 어그로 끌어 보았습니다

많은 개발자분들이 공부를 위해 클론 코딩을 종종 하곤 합니다. 아이디어를 낼 필요 없이 그냥 따라 하며 기술적인 공부에만 집중하면 되기 때문이죠.

그런 서비스들 중 무한 스크롤을 많이 사용하고 있고 그렇기 때문에 무한 스크롤을 구현하고 있습니다. 개인적인 생각으로 무한 스크롤은 하나의 주제로 프론트에서 다양한 것을 학습하기에 적합하기도 합니다. (예를 들면 event throttling, debounce 비동기 통신 등)

하지만 대부분의 사람들이 무한 스크롤을 구현할 때 간과하고 있는 부분이 있는데요, 바로 페이지네이션 입니다. 무한 스크롤은 일반적인 게시판 페이지네이션과 다릅니다.


예를 들어 여러분들이 인스타그램을 클론 코딩 하고, 피드를 불러오는 API를 /v1/timeline?page=n 으로 구현했다고 가정하겠습니다.

사용자가 첫 번째 페이지에 진입했습니다. 그렇기 때문에 1번 페이지에 있는 피드들을 서버에 요청합니다. 서버는 109번부터 100번까지의 10개의 피드를 응답합니다.

사용자가 처음 불러온 10개의 피드를 모두 읽었습니다. 서버에 2페이지의 피드를 요청합니다. 그런데, 10개의 피드를 읽던 와중에 10개의 피드가 더 업로드되었습니다.

서버는 2페이지의 피드를 요청했기 때문에 (page - 1) * 10 + 1번 피드부터 10개를 가져옵니다. 즉 기존에 불러왔던 109번부터 100번째 피드를 다시 요청합니다.

이러한 경우에는 프론트에서 중복된 피드를 한번 처리하게 되면 사용자 입장에서는 잘 모를 수 있습니다. 하지만 피드가 삭제되는 경우에는 어떻게 될까요?

119번부터 109번까지의 피드를 불러왔습니다. 사용자가 10개의 피드를 보는 동안 5개의 피드가 지워졌습니다.

114번부터 110까지 5개의 피드가 삭제된 상태에서는 사용자가 2페이지 피드를 요청했을 때 서버는 104번부터 95번까지 피드를 응답하게 될 것입니다. 그럼 사용자는 109번부터 105번까지 피드는 볼 수 없게 됩니다. 새로고침 해서 다시 1번 페이지부터 보지 않는 한에서 말이죠.

왜냐하면 페이지를 쓰면 백엔드에서는 현재 사용자가 어떤 피드까지 봤는지 알 수 있는 방법이 없기 때문입니다. 페이지를 꼭 쓰면 안 되는 것은 아니지만, 조금 더 나은 방법이 있습니다. 간단히 예제를 확인할 수 있는데요.

깃허브의 커밋 내역을 보다가 URL을 보신 적 있으신가요? 커밋 내역에서 Newer 혹은 Older 버튼을 누르게 되면 다음과 같이 URL이 되어있는 것을 볼 수 있습니다. 보시면 페이지가 아니라 현재 보고 있는 커밋 내역의 커밋 id를 서버로 보내고 있습니다. (/nestjs/nest/commits/master?after=커밋id)

즉 페이지가 없이 불러왔던 커밋을 기준으로 커밋 n개를 불러오기 때문에 페이지가 없습니다. 그렇기 때문에 깃허브에서 커밋 내역을 볼 때 화면 하단에 버튼이 1...n까지의 페이지가 아닌 Newer, Older 버튼을 눌러 넘겨가며 볼 수밖에 없는 것이죠.

이렇게 하면 커밋 내역을 보던 중 오랜 시간이 지나도 다음 페이지로 넘어갔을 때 커밋이 중복되어 보이지 않겠죠.

깃허브의 경우 Newer, Older로 이전과 이후 커밋을 불러와야 하기 때문에 리스트의 맨 위에 있는(가장 최근의) 커밋의 값을 기준으로 요청합니다.

이제는 실제로 인스타그램의 요청을 보겠습니다.

피드를 요청한 API의 응답 값인데요, next_max_id라는 값이 존재합니다. 이 값이 현재 응답받은 피드의 기준이 되는 값입니다.

그래서 다음 피드를 불러오는 API를 요청할 때 max_id에 그 값을 담아 요청을 보내게 됩니다.

profile
안녕하세요!

9개의 댓글

comment-user-thumbnail
2022년 4월 5일

글 내용과는 별개로 움짤이 매우 킹받지만 좋은글 감사합니다

1개의 답글
comment-user-thumbnail
2022년 4월 6일

페이지네이션이 꼭 페이지넘버를 기준으로 요청을 처리하는것만을 의미하지는 않습니다.

예를 들면 노션 API 의 데이터베이스 쿼리 스펙을 보시면, start_cursor 값과 page_length 를 사용한 쿼리 또한 페이지네이션이라고 부르고 있습니다. 물론 매 요청마다 next_cursor 를 응답에 넣어줘서 그다음 요청을 할수 있구요.

그러니까 페이지네이션을 쓰면 안된다 보다는, 페이지넘버만 사용하는 정적인 페이지네이션은 적합하지 않고, 여느 데이터베이스처럼 커서를 사용하는 페이지네이션을 써야된다고 말하는게 더 적합할것 같아요.

1개의 답글
comment-user-thumbnail
2022년 4월 9일

파이어스토어에서 시작 지점을 지정해서 하는 페이지네이션을 처음 봤을땐 좀 어색했던 경험이 있었는데 아무래도 이런 방법이 좀 좋아보이긴하네요 좋은글 감사합니다.

답글 달기
comment-user-thumbnail
2022년 4월 11일

데이터 캐싱을 자동으로 지원하는 리액트 쿼리를 쓰면 평화로워집니다 :-)

답글 달기
comment-user-thumbnail
2022년 4월 11일

I cannot understand a thing from this post. Yet i am commenting for no purpose. Hey people reading this, may your day become more fun and happy

답글 달기