browser · high priority
현대 Web APIs 실무 — Observer 패턴과 브라우저 API
IntersectionObserver, ResizeObserver, MutationObserver, Web Storage
intermediate 난이도3시간토스당근카카오네이버배민라인
시작 전
이해도
매우 낮음
학습 개요
탄생 배경
쉬운 설명
복잡한 개념을 실생활 비유로 설명합니다.
“보안 카메라와 경비원”
IntersectionObserver는 문 앞에 설치된 적외선 센서입니다. 누군가 들어오면 자동으로 알림이 옵니다. 매 초마다 "누가 들어왔나?" 확인하는 것(scroll 이벤트)보다 훨씬 효율적입니다. ResizeObserver는 방 크기를 자동으로 재는 스마트 자입니다.
핵심 개념
무한 스크롤 구현typescript
1// ✅ IntersectionObserver로 무한 스크롤2function useInfiniteScroll(onLoadMore: () => void) {3 const sentinelRef = useRef<HTMLDivElement>(null);45 useEffect(() => {6 const sentinel = sentinelRef.current;7 if (!sentinel) return;89 const observer = new IntersectionObserver(10 (entries) => {11 if (entries[0].isIntersecting) {12 onLoadMore(); // 리스트 끝에 닿으면 더 로드13 }14 },15 { threshold: 0.1 } // 10% 보이면 트리거16 );1718 observer.observe(sentinel);19 return () => observer.disconnect(); // 정리20 }, [onLoadMore]);2122 return sentinelRef;23}2425// 사용26function PostList() {27 const { posts, loadMore } = usePosts();28 const sentinelRef = useInfiniteScroll(loadMore);2930 return (31 <ul>32 {posts.map(post => <PostItem key={post.id} post={post} />)}33 <div ref={sentinelRef} /> {/* 이 요소가 보이면 로드 */}34 </ul>35 );36}
이미지 지연 로딩 (Lazy Loading)typescript
1function LazyImage({ src, alt }: { src: string; alt: string }) {2 const [loaded, setLoaded] = useState(false);3 const imgRef = useRef<HTMLImageElement>(null);45 useEffect(() => {6 const img = imgRef.current;7 if (!img) return;89 const observer = new IntersectionObserver(([entry]) => {10 if (entry.isIntersecting) {11 img.src = src; // 화면에 들어올 때 src 설정12 setLoaded(true);13 observer.disconnect();14 }15 });1617 observer.observe(img);18 return () => observer.disconnect();19 }, [src]);2021 return (22 <img23 ref={imgRef}24 alt={alt}25 style={{ opacity: loaded ? 1 : 0, transition: 'opacity 0.3s' }}26 />27 );28}29// 참고: 최신 브라우저는 <img loading="lazy" />로 더 간단하게 처리 가능
실무 적용
어떤 상황에서 사용하는가
뉴스 피드 앱의 무한 스크롤과 이미지 지연 로딩 구현
어떻게 적용하는가
IntersectionObserver로 피드 끝 sentinel 요소 감지 시 다음 페이지 로드. 이미지는 loading="lazy" 속성 또는 IntersectionObserver로 src 지연 설정. ResizeObserver로 카드 컨테이너 크기에 따라 1열/2열/3열 레이아웃 전환.
흔한 실수와 안티패턴
- observer.disconnect() 미호출로 메모리 누수 발생
- threshold 설정을 너무 높게 하면 끝에 도달하기 전에 로드가 안 됨
- SSR 환경에서 window/document에 접근 시 에러 — typeof window !== "undefined" 체크
- ResizeObserver 콜백에서 크기를 변경하면 무한 루프 발생 가능
면접 질문
중급토스당근카카오네이버배민
답변 방향 힌트
성능 차이, 구현 복잡도
반드시 언급할 키워드
- scroll 이벤트: 잦은 발생, throttle 필요
- IO: 브라우저 최적화 타이밍, 성능 우수
- cleanup 중요
예상 꼬리 질문
- rootMargin 옵션은 어떻게 사용하나요?
- React Query의 useInfiniteQuery와 함께 어떻게 연동하나요?