Reactでのスクロール連動エフェクトなら「react-intersection-observer」が良き

この記事は、株式会社エイチームフィナジー の [Advent Calendar 2020 6日目](https://qiita.com/advent-calendar/2020/ateam-finergy)の記事になります。

6日目は、React環境でスクロール連動エフェクトを実装する際に便利な `react-intersection-observer` について、ご紹介します。

## 背景
現在、React(JSフレームワーク) と Emotion(CSSinJS) を導入した環境でタスクを進めており、**特定の高さまでスクロールしてきた時にテキストにマーカーが引かれるやつ** を実装する機会がありました。

当初は、JavaScriptの`scroll`イベントや`window.pageYOffset`などを使って一度実装したのですが、この手法だとスクロールのたびに関数が呼び出されるため、パフォーマンスに影響を及ぼしてしまうようです。

`scroll`イベントの手法で実装後、ふとエンジニアから、「最近はこれで実装するのがパフォーマンスも軽くて良きです」と紹介されたのが、`Intersection Observer` でした。（名前がカッコ良い）

なるほど！と思った数日後には、エンジニア側で軽やかに`Intersection Observer` で実装完了されており、表示を確認すると、**特定の高さまでスクロールしてきた時にテキストにマーカーが引かれるやつ** がしっかり再現されていました。

今後同じような実装が必要になった時、自分の方でも軽やかに実装したいと思ったことと、
せっかくのReact環境ということで、今回は `react` と名前の付いた `react-intersection-observer` で実装を試してみました。


## Intersection Observer とは
「Intersection（要素間の交差）」を「Observe（監視）」するAPIのことです。
指定したDOM要素の交差点（DOM）を監視することができます。
[「Intersection Observer」の詳細はこちら](https://developer.mozilla.org/ja/docs/Web/API/Intersection_Observer_API)

ブラウザサポートも拡充しており、今後標準となる技術のようです。
[「Intersection Observer」の対応ブラウザはこちら](https://caniuse.com/intersectionobserver)


## react-intersection-observer とは
今回使用するライブラリ `react-intersection-observer` は、上記の `Intersection Observer API` をReactで簡単に扱うためのライブラリになります。
[「react-intersection-observer」の詳細はこちら](https://yarnpkg.com/package/react-intersection-observer)

## 何はともあれ実装
**$ yarn add** でライブラリ `react-intersection-observer` をインストールします。
（`package.json`と`yarn.lock`に react-intersection-observer が追加されます。）
```terminal
$ yarn add react-intersection-observer
```

コンポーネントに使用していきます。
```tsx:index.tsx
/** @jsx jsx */
import { FC } from "react";
import { jsx } from "@emotion/core";
import { styles } from "./Styled";

import { useInView } from 'react-intersection-observer';

export const index: FC = () => {
  // Hooksを使って簡単に書くことができます。
  // refで要素を指定して、inViewを使って要素がViewに入ったかどうかを判定します。
  // Optionについては、rootMarginを設定。要素が100pxより上に入った段階でinViewを取得できます。
  const [ref, inView] = useInView({
    rootMargin: '-100px 0px',
  });

  return (
    // スクロールして要素が表示されると同時に styles.show が付与される
    <p ref={ref} css={[styles.yellow, inView && styles.show]}>
      テキストテキスト
    </p>
  );
};

```

```ts:Styled.ts
import { css } from "@emotion/core";

export const styles = {
  // マーカー箇所のstyle
  yellow: css`
    width: 200px;
    margin: 0 auto;
    text-align: center;
    opacity: 0;
    transition: 2s;
    background: -webkit-linear-gradient(
      left,
      rgb(255, 250, 153) 50%,
      transparent 50%
    );
    background-repeat: no-repeat;
    background-size: 200% 0.8em;
    background-position: 100% 0.5em;
  `,

  // スクロールして要素が表示されると同時に付与されるstyle
  show: css`
    opacity: 1;
    background-position: 0% 0.5em;
    animation: SlideIn 3s ease-out both;
    transform: translateY(-10px);
  `,
};
```

ブラウザをスクロールして確認すると、テキスト箇所が表示される高さになった瞬間に、アニメーションが発火してくれました！（動き的には、ふわっと下から表示 + マーカーが左から引かれる）
![画面収録_黄色マーカー.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534817/d8da7a9b-7faf-02a4-fd79-f18901bc9f02.gif)

## 利用に便利なシチュエーション
* 特定の高さまでスクロールしてきた時にテキストにマーカーが引かれるやつ
* 画像の遅延ロード
* YouTubeの自動再生
* コンテンツの追加読み込み
などなど


## まとめ
いかがだったでしょうか？ 今回は React環境 で簡単に`Intersection Observer API`を使用することができる、`react-intersection-observer` をご紹介しました。
とても簡単で便利ですので、ぜひ一度使ってみてください。

## 参考
* [JSでのスクロール連動エフェクトにはIntersection Observerが便利](https://ics.media/entry/190902/)
* [使ってみよう！Intersection Observer！](https://qiita.com/ryo_hisano/items/42f5980720bc832e6e09)
* [ReactでIntersection Observer APIを使うにはreact-intersection-observerが便利](https://ryusou.dev/posts/react-intersection-observer)