무한 스크롤 🔫
사건
이번 주 과제 중에 제일 지독할 것만 같은 녀석이 있었다.
그것은 이름마저도 되게 부담스러운 “무한 스크롤”.
당연히 내가 한 것은 아니다.
출처 : @eunoia
무한 스크롤이란?
“무한 스크롤은 사용자가 페이지 하단에 도달했을 때, 콘텐츠가 계속 로드되는 사용자 경험(UX) 방식”
페이지 아래로 스크롤 하면 끝없이 새로운 화면을 보여주게 되고 이로 인해 많은 양의 콘텐츠를 볼 수 있는 것이다.
웹페이지를 탐방하면서 너무나도 당연하게 여기고 있던 기능을 구현하려니 막막했다.
무조건 어려울 것이 분명하여 미루고 미뤘지만 결국 무한스크롤을 건드려야 할 때가 왔다.
무한 스크롤 로직
- 페이지를 아래로 스크롤하며 맨 아래에 닿는 것을 인식하게 한다.
- 닿았을 때 추가로 데이터를 요청한다.
- 받아온 데이터를 통하여 새 영상 목록들과 그의 정보들을 보여준다.
- API Key가 유효할 때까지 무한정 영상들을 불러온다.
대충 로직은 이러했다.
그럼 우선 현재 보여주고 있는 화면의 스크롤 위치가 맨 아래에 닿았다는 것을 인식시키기 위해
window
나 document
의 프로퍼티 중 내가 사용할 수 있을만한 것을 찾아 보기로 했다.
[Element - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/Element#:~:text=10.3-,scrollHeight,-1) |
찾아 온 것은 다음과 같았다.
document.documentElement.scrollTop
: 위에서부터 스크롤 한 윈도우의 상단까지 길이document.documentElement.scrollHeight
: 전체 스크롤의 길이window.innerHeight
: 윈도우의 높이 길이
내가 이해한 바는 다음과 같았다.
위와 같이 맨 아래에 닿게 되면 scrollHeight
의 값이 scrollTop
값과 window.innerHeight
값을 더한 것과 같아지게 된다.
그 로직을 이용하면 될 것 같았다.
의사코드
우선 해당 의사코드를 어디에 써야할지 생각해봤는데 검새칸에 들어갈 키워드 입력값이 state로 저장되어 있는 곳에 넣는 것이 좋아 보였다.
scrollHeight
값이scrollTop
값과window.innerHeight
값을 더한 것과 같아졌을 때 데이터를 요청한다.- 받아온 데이터를 기존 데이터에 추가로 붙여준다.
- 새롭게 업데이트 된 데이터를 웹사이트에 렌더링 한다.
아래 영상은 1번이 만족됐을 때 잘 실행되는 가를 간단하게 실험해 봤다.
맨 아래에 닿았을 때 성공적으로 max
가 뜨는 것을 확인했다.
코드적으로 로직을 구현해보자면
useEffect
를 이용해scroll
을 할 때마다 어떤 함수를 실행시킨다.- 그 어떤 함수는 아무 동작을 하지않고 특정 조건에만 동작을 하는데
- 그 조건을 위 의사코드 1번을 만족했을 때만 동작하게 한다.
- 실제 동작하는 것은
fetch Data
이고 같은 키워드로 추가 데이터를 받아온다. - 받은 데이터를 변수에 할당 해주고 해당 변수를 기존 데이터에
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}®ionCode=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}®ionCode=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);
}
};
위 로직처럼 maxResult
도 prop
으로 받아주었고 스크롤 맨 밑을 닿을 때마다
최대 검색 결과 기존 state
값에 10을 더한 값으로 state
변경하는 방식을 사용해 주었다.
그리고 위의 useEffect
의 dependencies
에도 maxResult를 넣어 해당 값이 변경될 때마다
안의 콜백함수를 실행케 했다.
대망의 결과
일단 원하는 무한스크롤은 구현이 되었다!
하지만 찜찜한 느낌이 있었는데 기존 영상 밑에 새 영상을 추가해주는 것이 아닌
maxResult
값이 증가되어 증가된 값의 개수만큼 다시 새 영상 목록들을 리렌더링 해주는 것이었다.
원하는 결과가 아니었기에 실망감을 감출 수가 없었다.
useEffect말고도 추가로 다른 어떤 방법이 있나 추후에 조사를 해보고 다시 시도를 해보아야 할 것 같다.
실패!
“스러져간 키들을 추모하며”