바닐라 자바스크립트로 무한 스크롤 구현하고, React 라이브러리를 사용하여 응용해본 경험을 풀어 보았다.
바닐라 자바스크립트
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>한무스크롤</title>
<style>
html, body{ margin: 0;}
section .box{
height: 500px; background: tomato; color: white;
box-sizing: border-box; padding: 30px 10px;
}
section .box:nth-child(2n) { background: teal;}
</style>
</head>
<body>
<section>
<div class="box">1번째 블록</div>
<div class="box">2번째 블록</div>
</section>
<script>
let count = 2;
window.onscroll = () => {
if((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
const toAdd = document.createElement('div');
toAdd.classList.add('box')
toAdd.textContent = `${++count}번째 블록`
document.querySelector('section').appendChild(toAdd);
}
}
</script>
</body>
</html>
편의상 전체 코드를 붙여 놨습니다.
(window.innerHeight + window.scrollY) >= document.body.offsetHeight)
사실 상 위의 코드만 이해하면 내 것으로 만들 수 있습니다.
window.innerHeight = 현재 이 글을 보고있는 사용자의 창 높이
(개발자도구를 열어서 콘솔에 'document' 만 쳤을 때, 선택되는 부분의 높이!!)
본인의 현재창이 1000px일수도 500px일 수도 있습니다.
window.scrollY = 현재 스크롤의 Y
(제일 상단의 Y 입니다. 이것도 현재 창의 크기에따라 값이 다릅니다.)
위 두가지는 모니터의 크기에따라 다르게 나옵니다. 직접 개발자 도구를 열어서 눈으로 확인해 보세요.
아니면 이해가 안됨..
document.body.offsetHeight = body의 최상단에서 최하단까지의 높이값
(맨위부터 맨아래까지의 거리)
결론
window.innerHeight + window.scrollY = document.body.offsetHeight 입니다.
이벤트를 끄고, 위에 코드 기준 스크롤을 제일 아래로 내렸을 때
무한스크롤 발동 조건
window.innerHeight + window.scrollY >= document.body.offsetHeight
스크롤을 내릴때 마다 계속 변하는 window.scrollY의 변동에 따라 위의 조건을 만족 할때,
toAdd.classList.add('box')
toAdd.textContent = `${++count}번째 블록`
document.querySelector('section').appendChild(toAdd);
위의 태그를 추가한다.
React 에서 사용하기
구현 방법
window.innerHeight + window.scrollY >= document.body.offsetHeight
위의 조건이 만족 했을때, fetch 메서드로 데이터를 추가로 가져오고, useState로 hook을 일으켜서, 추가 렌더링을 한다.
import { useEffect, useState } from 'react';
const InfiniteScroll = () => {
const [feed,setFeed] = useState([])
const onScroll = () => {
if(window.innerHeight + window.scrollY >= document.body.offsetHeight) {
console.log(1)
fetch('data/infinit.json')
.then(response=> response.json())
.then(data=> setFeed([...feed,...data]))
}
}
useEffect(
()=>
fetch('data/infinit.json')
.then(response=>response.json())
.then(setFeed),
[]
)
useEffect(()=> {
window.addEventListener('scroll',onScroll);
return () =>window.removeEventListener('scroll',onscroll)
})
return feed.map(img => <img key={img.id} src={img.img} alt={img.id}/>)
}
export default InfiniteScroll
코드 전체를 가져오면 난잡해져서 일부분만 가져왔습니다.
여기서 핵심은 스크롤이 최하단으로 갈때마다, setFeed로 data를 누적시키면서 hook을 일으켜서,
리렌더링이 되는 것입니다.