LoginSignup
30
22

More than 1 year has passed since last update.

【React】あるHTML要素が画面内に表示されている時だけtrueを返すようなhooksを作る

Posted at

はじめに

Webアプリケーションを開発する中であるHTMLの要素が画面内にあるかどうか知りたいことはよくあります。例えば無限にデータを読み込む必要がある時はスクロールが一番下のコンテンツまで到達したという情報、つまり一番下のコンテンツが画面内にあるかどうかが必要となります。他にも、対象のコンテンツがユーザーに表示された数を計測したい時にも使えます。
この記事ではある要素が画面内に現れた時にtrue、存在しない時にfalseを返すようなCustom Hooksを作成します。

実装

今回作成するコードの全景はこのようになっています。

import { RefObject, useEffect, useState } from 'react';

export const useInView = (ref: RefObject<HTMLElement>) => {
  const [inView, setInView] = useState(false);

  useEffect(() => {
    if (!ref.current) {
      return;
    }

    const observer = new IntersectionObserver(([entry]) =>
      setInView(entry.isIntersecting),
    );
    observer.observe(ref.current);

    return () => {
      observer.disconnect();
    };
  }, [ref, setInView]);

  return inView;
};

引数には監視対象の要素を参照するようなrefを渡します。
そして、useStateを用いて監視対象の要素が画面内に現れたらtrueを返すような状態を作成します。ここで作成したinViewはこのhooksの返り値となります。

残りの部分は監視を行うように設定をするuseEffectです。

useEffect(() => {
  if (!ref.current) {
    return;
  }

  const observer = new IntersectionObserver(([entry]) =>
    setInView(entry.isIntersecting),
  );
  observer.observe(ref.current);

  return () => {
    observer.disconnect();
  };
}, [ref, setInView]);

まずは、余計なことを考えないようにref.currentがFalsyな値(このケースではnull)の時は監視対象の要素がrefで参照されていないと判断して早期returnします。
そして、refが監視対象の要素を参照するようになったら、交差オブザーバーAPIを用いて画面内にref.currentで参照している要素が表示されているときはinViewtrue、表示されていないときはfalseに設定させます。
この設定は異なるライフサイクル間で引き継ぐとバグの原因になるので、アンマウント時に解除されるようにクリーンアップ関数も書きます。

デモ

このhooksを利用方法の一例として以下のようなデモを作成しました。

refが画面内に現れている時だけ表示するメッセージが変わるようなコンポーネントになっています。

さいごに

ライブラリなどを利用せずに、ReactとブラウザAPIだけで簡単に作成することができるのでこれに近しいことがしたい場合はぜひご活用ください。

30
22
1

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
30
22