4
7

More than 1 year has passed since last update.

React×IntersectionObserverで実現する3つの強力なフィーチャー!

Posted at

要素がビューポート内にあるかどうかを監視するAPI、IntersectionObserver。これをReactと組み合わせれば、ユーザーエクスペリエンスを大幅に向上させることができます。この記事では、そんな組み合わせの力をフルに引き出す方法をご紹介します!

目次

  1. IntersectionObserverとは?
  2. ReactでIntersectionObserverを使うための基本
  3. 実践!3つのフィーチャー
    • Lazy Loading
    • インフィニティスクロール
    • 広告の表示率計測
  4. まとめ

IntersectionObserverとは?

IntersectionObserverは、特定の要素がビューポート(表示領域)内に入ったり出たりしたときを監視するためのAPIです。これにより、要素の表示/非表示を効果的に制御したり、特定のアクションをトリガーできます。

ReactでIntersectionObserverを使うための基本

ReactでIntersectionObserverを使う際は、主にuseRefuseEffectを組み合わせます。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を組み合わせることで、非常にパワフルなフィーチャーを簡単に実装できます。上記の例を参考にして、自分のプロジェクトに取り入れてみてください!

4
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
7