要素がビューポートに入ったかどうかを効率的に監視する
// ── IntersectionObserver: 要素が画面に入ったかを監視する ─
// 無限スクロール、遅延ロード、アニメーション開始に使う
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// 要素が画面内に入ったとき
console.log('画面に入った:', entry.target);
entry.target.classList.add('visible'); // アニメーション開始など
} else {
// 要素が画面外に出たとき
console.log('画面から出た:', entry.target);
}
});
}, {
root: null, // null = ビューポートを基準にする
rootMargin: '0px', // マージンを設定(例: '100px' で少し前に発火)
threshold: 0.5, // 要素の50%以上が見えたら発火(0〜1)
});
// 監視したい要素を登録
const target = document.querySelector('.lazy-image');
if (target) observer.observe(target);
// 監視を止める
observer.unobserve(target!); // 特定の要素を解除
observer.disconnect(); // 全て解除
// ── React での典型パターン ────────────────────────────
function LazyImage({ src }: { src: string }) {
const ref = useRef<HTMLDivElement>(null);
const [visible, setVisible] = useState(false);
useEffect(() => {
const obs = new IntersectionObserver(([e]) => {
if (e.isIntersecting) { setVisible(true); obs.disconnect(); }
});
if (ref.current) obs.observe(ref.current);
return () => obs.disconnect();
}, []);
return <div ref={ref}>{visible && <img src={src} alt="" />}</div>;
}scrollイベントより遥かに効率的。無限スクロールや遅延画像読み込み(lazy loading)の実装に最適。threshold配列で複数の閾値を指定できる。