FEInterview Prep

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);
4
5 useEffect(() => {
6 const sentinel = sentinelRef.current;
7 if (!sentinel) return;
8
9 const observer = new IntersectionObserver(
10 (entries) => {
11 if (entries[0].isIntersecting) {
12 onLoadMore(); // 리스트 끝에 닿으면 더 로드
13 }
14 },
15 { threshold: 0.1 } // 10% 보이면 트리거
16 );
17
18 observer.observe(sentinel);
19 return () => observer.disconnect(); // 정리
20 }, [onLoadMore]);
21
22 return sentinelRef;
23}
24
25// 사용
26function PostList() {
27 const { posts, loadMore } = usePosts();
28 const sentinelRef = useInfiniteScroll(loadMore);
29
30 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);
4
5 useEffect(() => {
6 const img = imgRef.current;
7 if (!img) return;
8
9 const observer = new IntersectionObserver(([entry]) => {
10 if (entry.isIntersecting) {
11 img.src = src; // 화면에 들어올 때 src 설정
12 setLoaded(true);
13 observer.disconnect();
14 }
15 });
16
17 observer.observe(img);
18 return () => observer.disconnect();
19 }, [src]);
20
21 return (
22 <img
23 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와 함께 어떻게 연동하나요?

학습 자료