eunsoolib
React 컴포넌트·훅

in-view

IntersectionObserver 기반 뷰포트 진입 감지 컴포넌트와 훅

설치

pnpm add @cbcruk/in-view react

브라우저 전용입니다.

사용법

컴포넌트

import { InView } from '@cbcruk/in-view'

function NextPageTrigger({ fetchNextPage, hasNextPage }: Props) {
  return (
    <InView onIntersect={fetchNextPage} enabled={hasNextPage} threshold={0.5}>
      <p>불러오는 중...</p>
    </InView>
  )
}

InView<div>를 렌더링하며, 나머지 prop(className 등)은 그 <div>로 전달됩니다.

import { useIntersectionObserver } from '@cbcruk/in-view'

function Sentinel({ onIntersect }: { onIntersect: () => void }) {
  const { ref } = useIntersectionObserver({ onIntersect })

  return <div ref={ref} />
}

onIntersect는 최신 참조를 내부 ref에 보관하므로 인라인 함수를 넘겨도 옵저버가 다시 만들어지지 않습니다. 옵저버는 enabled, threshold, root, rootMargin이 바뀔 때만 다시 만들어집니다.

<div>가 아닌 엘리먼트를 관찰하려면 타입 인자를 넘깁니다.

const { ref } = useIntersectionObserver<HTMLLIElement>({ onIntersect })

return <li ref={ref} />

API

useIntersectionObserver<T extends Element = HTMLDivElement>(options)

{ ref }를 반환합니다. ref(RefObject<T | null>)를 대상 엘리먼트에 연결하면, 대상이 교차 상태가 될 때마다 onIntersect를 호출합니다. 벗어났다가 다시 들어오면 다시 호출됩니다.

OptionTypeDefaultDescription
onIntersect() => void교차 상태가 됐을 때 호출 (항상 최신 함수)
enabledbooleantruefalse면 관찰하지 않음
thresholdnumber0.1IntersectionObserverthreshold
rootElement | Document | nullnull교차 판정 기준 엘리먼트. null이면 뷰포트
rootMarginstring'0px'기준 영역의 여백 (CSS margin 문법)

<InView />

위 훅의 옵션에 children: ReactNode(필수)를 더하고, <div>의 나머지 props를 받습니다. ref를 넘기면 관찰 대상 <div>에 함께 연결됩니다(객체 ref, 콜백 ref 모두 지원).

제약

  • InView는 항상 <div>를 렌더링합니다. 다른 엘리먼트가 필요하면 훅을 직접 사용하세요.
  • 훅의 ref는 객체 ref라서, 마운트 이후 대상 엘리먼트 자체가 다른 노드로 바뀌면 옵션이 바뀔 때까지 새 노드를 관찰하지 않습니다.
  • root에 엘리먼트를 넘길 때는 렌더링 시점에 실제 엘리먼트가 있어야 합니다(state에 담은 노드 등). 렌더 중 ref.current는 첫 렌더에 null입니다.

On this page