要素がビューポート内にあるかどうかを監視するAPI、IntersectionObserver
。これをReactと組み合わせれば、ユーザーエクスペリエンスを大幅に向上させることができます。この記事では、そんな組み合わせの力をフルに引き出す方法をご紹介します!
目次
- IntersectionObserverとは?
- ReactでIntersectionObserverを使うための基本
- 実践!3つのフィーチャー
- Lazy Loading
- インフィニティスクロール
- 広告の表示率計測
- まとめ
IntersectionObserverとは?
IntersectionObserver
は、特定の要素がビューポート(表示領域)内に入ったり出たりしたときを監視するためのAPIです。これにより、要素の表示/非表示を効果的に制御したり、特定のアクションをトリガーできます。
ReactでIntersectionObserverを使うための基本
ReactでIntersectionObserver
を使う際は、主にuseRef
とuseEffect
を組み合わせます。useRef
でDOM要素を取得し、useEffect
内でその要素を監視するオブザーバーを設定します。
実践!3つのフィーチャー
1. Lazy Loading
Lazy Loadingは、要素(特に画像や動画)をページ読み込み時にすぐに読み込むのではなく、必要になったとき(例: スクロールして要素がビューポートに近づいたとき)に読み込む技術です。
コード例
import React, { useState, useEffect, useRef } from 'react';
function LazyImage({ src, alt, ...props }) {
const [isLoaded, setIsLoaded] = useState(false);
const imgRef = useRef(null);
useEffect(() => {
const observer = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting) {
imgRef.current.src = src;
imgRef.current.onload = () => setIsLoaded(true);
observer.disconnect();
}
});
observer.observe(imgRef.current);
return () => observer.disconnect();
}, [src]);
return <img ref={imgRef} alt={alt} {...props} style={isLoaded ? {} : { opacity: 0 }} />;
}
解説
-
useState
で画像の読み込み状態を管理します。 -
useRef
を使って画像要素への参照を保持します。 -
useEffect
内で、要素がビューポート内に入ったかどうかを監視するオブザーバーを設定します。 - 画像がビューポート内に入ると、実際の
src
を設定し、画像を読み込みます。
2. インフィニティスクロール
ページの最下部に達したときに、次のコンテンツを自動的に読み込む技術です。SNSなどでよく見られます。
コード例
import React, { useState, useEffect, useRef } from 'react';
function InfinityScroll({ fetchData }) {
const [items, setItems] = useState([]);
const loadingRef = useRef(null);
useEffect(() => {
const observer = new IntersectionObserver(async ([entry]) => {
if (entry.isIntersecting) {
const newItems = await fetchData();
setItems(prevItems => [...prevItems, ...newItems]);
}
});
if (loadingRef.current) {
observer.observe(loadingRef.current);
}
return () => observer.disconnect();
}, [fetchData]);
return (
<div>
{items.map(item => (
<div key={item.id}>{item.name}</div>
))}
<div ref={loadingRef}>Loading...</div>
</div>
);
}
解説
- 読み込み中のステータスを表示する要素(この例では"Loading...")を監視します。
- この要素がビューポート内に入ると、次のデータをフェッチし、既存のアイテムリストに追加します。
3. 広告の表示率計測
広告がビューポートにどれだけの時間表示されていたかを計測します。これは、広告の課金基準などで使用されることがあります。
コード例
import React, { useEffect, useRef } from 'react';
function AdComponent({ src }) {
const adRef = useRef(null);
const startTimeRef = useRef(null);
useEffect(() => {
const observer = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting) {
startTimeRef.current = new Date();
} else if (startTimeRef.current) {
const duration = new Date() - startTimeRef.current;
console.log(`Ad was visible for ${duration}ms`);
startTimeRef.current = null;
}
});
if (adRef.current) {
observer.observe(adRef.current);
}
return () => observer.disconnect();
}, []);
return <img ref={adRef} src={src} alt="Advertisement" />;
}
解説
- 広告がビューポートに表示された開始時間を記録します。
- 広告がビューポートから出ると、表示された時間を計算し、それをログに出力します。
まとめ
ReactとIntersectionObserver
を組み合わせることで、非常にパワフルなフィーチャーを簡単に実装できます。上記の例を参考にして、自分のプロジェクトに取り入れてみてください!