무한 스크롤은 어떻게 구현해야 되는가?
- 스크롤을 통해 컨텐츠의 끝 부분을 감지한다.
- 다음에 나올 컨텐츠들을 불러와 현재 페이지에 붙인다.
과정
- state 설정
- postList: 배열안에 객체의 형태를 가진 데이터를 넣는다.
- items: 현재 가져올 데이터의 개수를 정한다.
- prevItems: 이전에 가졌던 데이터의 개수
const [postData, setPostData] = useState({
postList: [],
items: 5,
prevItems: 0,
});
- 지정한 개수에 맞는 데이터 가져오기
- 최초 렌더링시 가져올 데이터의 개수는 5개로 잡는다.
- slice 메서드를 이용해서 0 ~ 5개의 데이터를 Mock 데이터에서 가져와서 sliceData 변수에 저장한다.
- postData에 들어있는 postList에 sliceData를 적용한다.
useEffect(() => {
const checkStatus = res => {
if (!res.ok) throw new Error(`Again Check Status: ${res.status}`);
return res.json();
};
const uploadPostData = data => {
const { postList, preItems, items } = postData;
const sliceData = data.slice(preItems, items);
setPostData({ ...postData, postList: [...postList, ...sliceData] });
};
const getPosts = url =>
fetch(url, {
method: 'GET',
});
getPosts('/data/post.json')
.then(checkStatus)
.then(uploadPostData)
.catch(error => console.error(error));
}, [postData.items]);
- 스크롤이 끝나기 직전에 새로운 데이터 가져오기
Element size and scrolling 참고
document.documentElement
을 이용하여 geometry property
(기하 프로퍼티)에 접근해서 우리가 필요한 속성을 가져온다. (scrollTop, clientHeight, scrollHeight)
- 가져온 속성을 이용해서 데이터를 가지고 온 뒤에도 높이를 계산할 수 있게 만든다. (scrollRatio)
- 브라우저나 기기마다 차이가 있을 수 있어서 0.95 값을 적용하여 보다 더 자연스럽게 해준다.
- 밑에 코드에서 Math.max 함수가 있는데 이건 사이트 전체를 컨트롤하는거라면
document.documentElement
의 값만을 참조하는 것은 위험할 수 있다고 해서 좀 더 정확하게 하기 위해서 body에 담겨있는 geometry값과 비교해서 가장 큰 값으로 사용했다.
const onScroll = () => {
const { items } = postData;
const { documentElement, body } = document;
const scrollTop = Math.max(documentElement.scrollTop, body.scrollTop);
const clientHeight = documentElement.clientHeight;
const scrollHeight = Math.max(
documentElement.scrollHeight,
body.scrollHeight
);
const scrollRatio = (scrollTop + clientHeight) / scrollHeight;
if (scrollRatio > 0.95) {
setPostData({ ...postData, items: items + 5, preItems: items });
}
};
useEffect(() => {
window.addEventListener('scroll', onScroll);
return () => {
window.removeEventListener('scroll', onScroll);
};
}, [onScroll]);