포스트

무한 스크롤 🔫

무한 스크롤 🔫

사건

이번 주 과제 중에 제일 지독할 것만 같은 녀석이 있었다.
그것은 이름마저도 되게 부담스러운 “무한 스크롤”.

images_eunoia_post_5beb6d18-1589-4c85-84bd-fc6d85c42b4e_infinityScroll.gif

당연히 내가 한 것은 아니다.
출처 : @eunoia

무한 스크롤이란?

“무한 스크롤은 사용자가 페이지 하단에 도달했을 때, 콘텐츠가 계속 로드되는 사용자 경험(UX) 방식”
페이지 아래로 스크롤 하면 끝없이 새로운 화면을 보여주게 되고 이로 인해 많은 양의 콘텐츠를 볼 수 있는 것이다.
웹페이지를 탐방하면서 너무나도 당연하게 여기고 있던 기능을 구현하려니 막막했다.
무조건 어려울 것이 분명하여 미루고 미뤘지만 결국 무한스크롤을 건드려야 할 때가 왔다.

무한 스크롤 로직

  1. 페이지를 아래로 스크롤하며 맨 아래에 닿는 것을 인식하게 한다.
  2. 닿았을 때 추가로 데이터를 요청한다.
  3. 받아온 데이터를 통하여 새 영상 목록들과 그의 정보들을 보여준다.
  4. API Key가 유효할 때까지 무한정 영상들을 불러온다.

대충 로직은 이러했다.

그럼 우선 현재 보여주고 있는 화면의 스크롤 위치가 맨 아래에 닿았다는 것을 인식시키기 위해
windowdocument의 프로퍼티 중 내가 사용할 수 있을만한 것을 찾아 보기로 했다.

[Element - Web APIsMDN](https://developer.mozilla.org/en-US/docs/Web/API/Element#:~:text=10.3-,scrollHeight,-1)

찾아 온 것은 다음과 같았다.

  1. document.documentElement.scrollTop : 위에서부터 스크롤 한 윈도우의 상단까지 길이
  2. document.documentElement.scrollHeight : 전체 스크롤의 길이
  3. window.innerHeight : 윈도우의 높이 길이

내가 이해한 바는 다음과 같았다.

무제.gif

위와 같이 맨 아래에 닿게 되면 scrollHeight의 값이 scrollTop 값과 window.innerHeight 값을 더한 것과 같아지게 된다.
그 로직을 이용하면 될 것 같았다.

의사코드

우선 해당 의사코드를 어디에 써야할지 생각해봤는데 검새칸에 들어갈 키워드 입력값이 state로 저장되어 있는 곳에 넣는 것이 좋아 보였다.

  1. scrollHeight 값이 scrollTop 값과 window.innerHeight 값을 더한 것과 같아졌을 때 데이터를 요청한다.
  2. 받아온 데이터를 기존 데이터에 추가로 붙여준다.
  3. 새롭게 업데이트 된 데이터를 웹사이트에 렌더링 한다.

아래 영상은 1번이 만족됐을 때 잘 실행되는 가를 간단하게 실험해 봤다.
맨 아래에 닿았을 때 성공적으로 max가 뜨는 것을 확인했다.

코드적으로 로직을 구현해보자면

  1. useEffect를 이용해 scroll을 할 때마다 어떤 함수를 실행시킨다.
  2. 그 어떤 함수는 아무 동작을 하지않고 특정 조건에만 동작을 하는데
  3. 그 조건을 위 의사코드 1번을 만족했을 때만 동작하게 한다.
  4. 실제 동작하는 것은 fetch Data이고 같은 키워드로 추가 데이터를 받아온다.
  5. 받은 데이터를 변수에 할당 해주고 해당 변수를 기존 데이터에 concat() 해준다.

문제 직면

해당 코드가 무안해질 정도로 너무 다른 결과를 보여줬다.
무한 스크롤에 필요한 추가 스크롤과 새 영상 목록들이 추가되지 않았다.

고찰

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const handleScroll = () => {
    if (
      window.innerHeight + document.documentElement.scrollTop + 1 >=
      document.documentElement.scrollHeight
    ) {
      const getData = async (search) => {
        const endpoint = window.encodeURI(
          `https://youtube.googleapis.com/youtube/v3/search?part=snippet&maxResults=15&q=${search}&regionCode=KR&type=video&key=${YOUTUBE_API_KEY}`
        );
        const res = await fetch(endpoint);
        const { items } = await res.json();
        return items;
      };
      setSearchData(searchData.concat(getData("입력값")));
    }
  };

위의 방식을 다시 보자면 바닥에 닿았을 때마다 해당 handleScroll 함수 내의 getData
“입력값”을 넣어 실행 해주고 fetch를 통해 받아온 데이터를 기존 데이터에 concat()
해주는 방식이면 되겠다 싶었지만 실패하였다.

발전

다른 방식으로는 어떻게 접근할 수 있을까 생각을 해보았고 생각해 낸 방법은 다음과 같았다.
복잡하게 추가로 fetch 데이터를 받아올 필요없이 원래 기존 결과를 받아오는
fetch 함수 url의 maxResult(최대 검색결과)에 접근하는 것은 어떨까 했다.

해당 방식은 이러했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  useEffect(() => {
    const getData = async (search) => {
      const endpoint = window.encodeURI(
        `주소 어쩌고...&maxResults=${maxResults}&q=${search}&regionCode=KR&type=video&key=${YOUTUBE_API_KEY}`
      );
      const res = await fetch(endpoint);
      const { items } = await res.json();
      setSearchData(items);
    };

    getData("입력값"); // 편의상 매번 업데이트 되는 입력값을 좌측처럼 변경하였다. 원래는 state
  }, [q, maxResults]);

  const handleScroll = () => {
    if (
      window.innerHeight + document.documentElement.scrollTop + 1 >=
      document.documentElement.scrollHeight
    ) {
      setMaxResults((prev) => prev + 10);
    }
  };

위 로직처럼 maxResultprop으로 받아주었고 스크롤 맨 밑을 닿을 때마다
최대 검색 결과 기존 state 값에 10을 더한 값으로 state 변경하는 방식을 사용해 주었다.
그리고 위의 useEffectdependencies에도 maxResult를 넣어 해당 값이 변경될 때마다
안의 콜백함수를 실행케 했다.

대망의 결과

무제.gif

일단 원하는 무한스크롤은 구현이 되었다!
하지만 찜찜한 느낌이 있었는데 기존 영상 밑에 새 영상을 추가해주는 것이 아닌
maxResult 값이 증가되어 증가된 값의 개수만큼 다시 새 영상 목록들을 리렌더링 해주는 것이었다.
원하는 결과가 아니었기에 실망감을 감출 수가 없었다.
useEffect말고도 추가로 다른 어떤 방법이 있나 추후에 조사를 해보고 다시 시도를 해보아야 할 것 같다.

실패!

설명

“스러져간 키들을 추모하며”

이 글은 저작권자의 CC BY 4.0 라이센스를 따릅니다.