0 day streak
javascript / expert
Snippet

Custom Hook: useIntersectionObserver with Ref Stability and Callback Refs

Using a state-based callback ref ([setNode]) instead of a standard useRef ensures the IntersectionObserver correctly re-attaches if the element is conditionally rendered. This pattern is essential for performant lazy-loading and infinite scroll in React.

snippet.js
javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { useState, useEffect, useRef } from 'react';
export function useIntersectionObserver(options: IntersectionObserverInit) {
const [entry, setEntry] = useState<IntersectionObserverEntry | null>(null);
const [node, setNode] = useState<Element | null>(null);
const observer = useRef<IntersectionObserver | null>(null);
useEffect(() => {
if (observer.current) observer.current.disconnect();
observer.current = new IntersectionObserver(([e]) => setEntry(e), options);
if (node) observer.current.observe(node);
return () => observer.current?.disconnect();
}, [node, options]);
return [setNode, entry] as const;
}
nextjs
Breakdown
1
const [node, setNode] = useState
Using a state-based callback ref to ensure the observer re-binds when the DOM element changes.
2
observer.current.disconnect()
Crucial cleanup to prevent memory leaks and redundant observations when dependencies change.