throttle과 IntersectionObserver API를 활용하여 Infinity Scroll을 라이브러리 없이 구현했습니다. 직접 구현하면서 여러 모듈을 조합하여 성능을 최적화하고, 부드럽게 데이터를 로드하기 위해 상당한 고민이 필요했습니다. 특히 throttle로 스크롤 이벤트를 제어하고, IntersectionObserver로 뷰포트 내 요소가 감지될 때만 데이터를 추가 요청하도록 구성한 부분이 핵심이었습니다.
1. IntersectionObserver 적용 Infinity Scroll 구현
...
function ScrollComponent() {
...생략
const endRef = useRef(null); // Infinite Scroll 구현을 위한 Ref 객체
/**
* 서버에 데이터가 더 있는 경우 데이터를 요청하고 redux store에 추가
*/
const fetchMoreIdols = useCallback(() => {
if (nextCursor) dispatch(getIdols({cursor: nextCursor, pageSize: 16}));
}, [nextCursor, dispatch]);
/**
* initial load
*/
useEffect(() => {
dispatch(getIdols({pageSize: 16}));
}, [dispatch]);
/**
* 감시 대상이 화면에 노출되면 서버에 데이터 요청
*/
const handleObserver = useCallback(
([entry]) => {
if (entry.isIntersecting) fetchMoreIdols();
},
[fetchMoreIdols],
);
/**
* IntersectionObserver API를 이용해 endRef 객체가 화면에 노출됨을 감지
*/
useEffect(() => {
if (device === 'desktop' || !endRef.current) return;
const observer = new IntersectionObserver(handleObserver, {
root: endRef.current.parentNode,
threshold: 1.0,
});
observer.observe(endRef.current);
return () => observer.disconnect();
}, [handleObserver, device]);
...생략
return (
<>
<Pagination
...생략
>
<div className="add-artists-wrap">
...생략(데이터 영역)
{device !== 'desktop' && <div ref={endRef} className="end-point" />}
</div>
</Pagination>
...생략
</>
);
}
export default ScrollComponent;
- endRef라는 useRef 객체를 생성합니다. 이 객체는 무한 스크롤의 기준이 되는 요소를 참조합니다.
- handleObserver 함수는 IntersectionObserver가 관찰하는 요소가 뷰포트에 들어올 때(isIntersecting이 true) fetchMoreIdols를 호출하도록 합니다.
- IntersectionObserver가 생성됩니다. 관찰 기준을 endRef.current.parentNode로 설정하고, threshold를 1.0으로 설정하여 요소가 완전히 뷰포트에 들어왔을 때만 트리거되도록 합니다.
- observer.observe(endRef.current)을 통해 endRef 요소를 감시합니다.
- return문에서 observer.disconnect()를 통해 컴포넌트가 언마운트되거나 리렌더링될 때 관찰을 해제합니다.
2. IntersectionObserver 적용 화면
이전 포스팅에서 다뤘던 Lodash 라이브러리의 throttle과 IntersectionObserver API를 응용해서 라이브러리를 사용하지 않고 직접 Infinity Scroll을 구현했습니다.
이번 프로젝트에서는 throttle과 IntersectionObserver API를 활용해 무한 스크롤 기능을 직접 구현하면서, 성능 최적화와 API의 세부 옵션 설정을 통해 많은 배움을 얻었습니다. 사실 라이브러리를 사용했더라면 더 높은 성능과 효율을 확보할 수 있었겠지만, 이번 경험을 통해 API의 동작 원리를 깊이 이해하고 문제 해결 능력을 키우는 좋은 기회가 되었습니다. 검색과 테스트 과정을 거쳐 직접 구현하면서 성능과 사용자 경험을 고려한 무한 스크롤 구현 방법을 체득할 수 있었습니다.
'개발 공부 일지 > React' 카테고리의 다른 글
[React] Compound Component Pattern (4) | 2024.11.15 |
---|---|
[React] Render Props Pattern (2) | 2024.11.14 |
[React] 리액트 useMemo (성능 최적화) (1) | 2024.10.21 |
[React] 리액트 생명 주기(Life Cycle) (3) | 2024.10.18 |
[React] 리액트 useReducer (0) | 2024.10.16 |