useIntersectionObserver in React

From the React Custom Hooks cheat sheet · Interaction & Lifecycle Hooks · verified Jul 2026

useIntersectionObserver

Detect when an element enters the viewport - lazy load, infinite scroll

jsx
import { useEffect, useRef, useState } from 'react'

function useIntersectionObserver(options?: IntersectionObserverInit) {
  const ref = useRef<HTMLElement>(null)
  const [entry, setEntry] = useState<IntersectionObserverEntry>()
  useEffect(() => {
    const el = ref.current
    if (!el) return
    const io = new IntersectionObserver(([e]) => setEntry(e), options)
    io.observe(el)
    return () => io.disconnect()
  }, [options?.root, options?.rootMargin, options?.threshold])
  return { ref, entry, isIntersecting: !!entry?.isIntersecting }
}

// Usage
function LazyImage({ src, alt }: { src: string; alt: string }) {
  const { ref, isIntersecting } = useIntersectionObserver({ rootMargin: '200px' })
  return (
    <div ref={ref as any}>
      {isIntersecting ? <img src={src} alt={alt} /> : <div className="placeholder" />}
    </div>
  )
}
💡 IntersectionObserver beats scroll listeners - browser-optimized, throttled by default
⚡ `rootMargin: "200px"` pre-fetches BEFORE the element is on screen
📌 freezeOnceVisible prevents re-triggering for one-shot animations
🎯 Sentinel + this hook is the cleanest infinite-scroll pattern in React
scrolllazy-loadperformance

More React tasks

Back to the full React Custom Hooks cheat sheet