pebblepark
개발계발
pebblepark
전체 방문자
오늘
어제
  • 분류 전체보기 (24)
    • Frontend (7)
    • Backend (7)
    • 인프라 (1)
    • CS (0)
      • Design Pattern (0)
    • 정리용 (9)
    • 회고 (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 스프링 컨테이너
  • React Query
  • spring
  • vite
  • react-query
  • typescript
  • @ModelAttribute
  • github
  • CORS
  • Github Pages
  • ERR_UNSAFE_PORT
  • 리액트쿼리
  • 호이스팅
  • Context API
  • 무한스크롤
  • debounce
  • redux
  • SpringMVC
  • springboot
  • react
  • 스프링
  • wsl
  • Docker
  • javascript
  • 스프링 의존관계
  • Git
  • hoisting
  • 스프링 빈
  • useLayoutEffect
  • TDZ

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
pebblepark
Frontend

Intersection Observer API를 활용한 무한스크롤 구현

Frontend

Intersection Observer API를 활용한 무한스크롤 구현

2022. 8. 17. 13:06

Intersection Observer API란

Intersection Observer API는 타겟 요소와 상위 요소 또는 최상위 document 의 viewport 사이의 intersection 내의 변화를 비동기적으로 관찰하는 방법입니다.
- MDN

화면 상의 Target Element 노출 여부를 감지하는 API 이다.

 

스크롤 이벤트 감지 방법과의 비교

  • scroll event를 감지하여 구현한다. 이때 throttle 혹은 debounce 과 같은 처리가 추가로 필요하며 throttle/debounce 를 사용하는 경우 쓰레드 메모리를 차지하고 성능에도 좋지않다.
  • scrollTop + window.clientHeight 등을 사용해서 끝에 도달했는지 계산한다. 이때clientHeight이나 offsetTop 같은 엘리먼트의 위치를 가져와서 계산해야 하는 값은 브라우저가 정확한 값을 구하기 위해 렌더링 큐에 쌓인 모든 작업을 수행하면서 Reflow 를 발생시킬 수 있다.

 

Intersection Observer Syntax

new IntersectionObserver (callback[, options]);

callback 함수는 다음과 같이 2개의 매개변수를 받는다.

  • entries
    👉 더 드러나거나 가려지면서 지정한 역치를 넘어가게 된 요소를 나타내는 IntersectionObserverEntry 객체의 배열
  • observer
    👉 자신을 호출한 IntersectionObserver

자세한 설명은 mdn 참고

 

IntersectionObserver() - Web API | MDN

IntersectionObserver() 생성자는 새로운 IntersectionObserver 객체를 생성하고 반환합니다.

developer.mozilla.org

 

무한 스크롤 구현

간단하게 구현하고자 하는 것은 아래와 같다.

- 리스트 목록 보여주기
- 스크롤 시 리스트 끝에 도달하면 새로운 리스트 추가

 

먼저, 리스트 목록을 보여줄 엘리먼트(ul)와 Intersection Observer의 target 엘리먼트(div)를 추가했다.

<ul id="list"></ul>
<div id="observer"></div>

다음으로, 리스트 목록을 추가하는 함수를 구현했다. 한 번 호출시마다 li 를 10개씩 추가한다.

let count = 0;
const $ul = document.getElementById('list');
function makeListElement() {
Array(10)
.fill(0)
.forEach(() => {
const $li = document.createElement('li');
$li.textContent = ++count;
$ul.appendChild($li);
});
}

마지막으로, 무한스크롤을 구현하는 부분이다. Intersection Observer의 타겟 엘리먼트가 화면에 보여질 때(isIntersecting) 리스트의 목록을 추가했다. 이때 API 호출시 생기는 딜레마를 표현하기 위해서 1초의 timeout을 지정했다.

let timer;
const $observer = document.getElementById('observer');
const io = new IntersectionObserver((entries) => {
clearTimeout(timer);
if (entries[0].isIntersecting) {
timer = setTimeout(() => makeListElement(), 1000);
}
});
io.observe($observer); // observer에 target element 등록

즉, 무한스크롤이 일어나는 과정은 다음과 같다.

  1. ul 태그 밑에 있는 target Element가 화면에 노출된다. (= 리스트의 끝에 도달했다)
  2. 1초의 딜레마 후 리스트에 10개의 엘리먼트가 추가된다.
  3. ul 태그에 자식 엘리먼트가 추가되면서 화면에는 새로 추가된 자식 엘리먼트가 보여진다. target Element 부분은 리스트의 맨 밑으로 이동하여 화면에 보여지지 않게 된다.
  4. 다시 스크롤을 통해 맨 밑으로 내리면(=리스트에 끝에 도달하면) target Element가 화면에 노출되면서 리스트를 추가한다.

 

전체코드

전체코드는 다음과 같다. 실행결과는 Demo에서 확인해볼 수 있다.

<!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>Infinite Scroll</title>
<style>
ul {
list-style-type: none;
display: flex;
flex-direction: column;
align-items: center;
padding: 0;
}
li {
background: #fff3bf;
border-radius: 2px;
margin: 1rem;
padding: 20% 0;
text-align: center;
font-size: 100px;
width: 80%;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
}
li:nth-child(2n) {
background-color: #c3fae8;
}
li:hover {
box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25),
0 10px 10px rgba(0, 0, 0, 0.22);
}
#observer {
width: 50px;
height: 50px;
margin: 30px auto;
border: 5px solid rgba(0, 0, 0, 0.12);
border-radius: 50%;
border-top-color: #c3fae8;
animation: spin 1s ease-in-out infinite;
-webkit-animation: spin 1s ease-in-out infinite;
}
@keyframes spin {
to {
-webkit-transform: rotate(360deg);
}
}
@-webkit-keyframes spin {
to {
-webkit-transform: rotate(360deg);
}
}
</style>
</head>
<body>
<ul id="list"></ul>
<div id="observer"></div>
<script>
let count = 0;
const $ul = document.getElementById('list');
function makeListElement() {
Array(10)
.fill(0)
.forEach(() => {
const $li = document.createElement('li');
$li.textContent = ++count;
$ul.appendChild($li);
});
}
makeListElement();
let timer;
const $observer = document.getElementById('observer');
const io = new IntersectionObserver((entries) => {
clearTimeout(timer);
if (entries[0].isIntersecting) {
timer = setTimeout(() => makeListElement(), 1000);
}
});
io.observe($observer);
</script>
</body>
</html>

 

 

저작자표시 (새창열림)

'Frontend' 카테고리의 다른 글

React-Query 정리  (0) 2022.08.05
[Javascript] Throttle 과 Debounce  (0) 2022.05.12
[Redux] 간단한 예제로 살펴보는 리덕스의 동작 원리  (0) 2022.03.17
[React] ContextAPI & useContext Hook을 통한 Global State 값 관리하기  (0) 2022.03.11
[Javascript] 변수, 호이스팅, TDZ  (0) 2022.03.07
  • Intersection Observer API란
  • 스크롤 이벤트 감지 방법과의 비교
  • Intersection Observer Syntax
  • 무한 스크롤 구현
  • 전체코드
'Frontend' 카테고리의 다른 글
  • React-Query 정리
  • [Javascript] Throttle 과 Debounce
  • [Redux] 간단한 예제로 살펴보는 리덕스의 동작 원리
  • [React] ContextAPI & useContext Hook을 통한 Global State 값 관리하기
pebblepark
pebblepark
프론트엔드 개발자입니다. 피드백은 언제나 환영입니다:)

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.