Next.js

「Next.js(React) + GSAP」でアニメーションを実装する

Webページでアニメーションを使用する場合は、便利なライブラリ「GSAP」を使用しております。
特にスクロールして要素が入った時に、アニメーションしながら表示するサイトでは「ScrollTrigger」と組み合わせて使用すると楽に実装できます。

https://greensock.com/gsap/

ただ「Next.js」で使用する場合は「GSAP」を使用するタイミングなどで悩みました。
特に「ScrollTrigger」は「useRef」を使用する必要などもありました。

環境

  • Mac Intel Ventura 13.1
  • TypeScript 4.9.5
  • Next.js 13.2.3
  • React 18.2.0
  • yarn 1.22.17
  • GSAP 3.11.4

導入方法

以下のコマンドで、「GSAP」をインストールする。

$ yarn add gsap

importする場合は、以下のように定義します。

// GSAP のインポート
import Gsap from 'gsap';

// ScrollTrigger のインポート
import { ScrollTrigger } from 'gsap/dist/ScrollTrigger';

// ScrollTriggerの初期化
Gsap.registerPlugin(ScrollTrigger);
Gsap.config({
    nullTargetWarn: false,
});

画面表示時に「GSAP」でアニメーションする

「Next.js」で「GSAP」を使用する場合、「useEffect」内に設定を定義します。
SSRとクライアントサイドの両方で画面作成後に「GSAP」の処理が行われます。

import React, {useEffect} from 'react';
import Box from '@mui/material/Box';
import Gsap from 'gsap';

const FadeInBox  = () => {

    // レイアウト作成後の動作
    useEffect(() => {

        // フェードイン表示する
        Gsap.to('#fadeInBox', { 
                opacity: 1,
                duration: 0.5
            });

    }, []);

    // Render
    return (
        <div className="fade">
            <div className="fade_init" id="fadeInBox" >BOX</div>
        </div>
    );
}

「ScrollTrigger」を使ってスクロール時にアニメーション

「Next.js」で「ScrollTrigger」を使用する場合、少し工夫が必要となります。
特にIDを指定する場合は通常の使い方と同じですが、クラスを指定する場合では少し工夫して使用します。
例えば同じレイアウトを繰り返して表示するコンテンツ等では通常はクラス(「.」から始まる要素)を指定しますが、「Next.js」の場合には「useRef」を使用します。

import React, {useEffect} from 'react';
import Box from '@mui/material/Box';
import Gsap from 'gsap';
import { ScrollTrigger } from 'gsap/dist/ScrollTrigger';

// ScrollTriggerの初期化
Gsap.registerPlugin(ScrollTrigger);
Gsap.config({
    nullTargetWarn: false,
});

const FadeInBoxes  = () => {
    const ref = useRef(null);

    const layouts = [1,2,3]

    // レイアウト作成後の動作
    useEffect(() => {
        // スクロールして要素が表示されるとフェードイン表示する
        Gsap.to(ref.current, {
            scrollTrigger: {
                trigger: ref.current,
                start: 'top center',
                once: true,
            },
            opacity: 1,
            duration: 1
        });
    }, [ref]);

    // Render
    return (
        <div className="fade">
            layouts.map((layout)=>(
                <>
                    {/* 「ref」を設定する */}
                    <div className="fade_init" id="fadeInBox" ref={ref} >{layout}</div>
                </>
            ))
        </div>
    );
}

また使用する場合は「components」で作成した方が確実かと思われます。
この辺りは慣れて行くしかないかなと思います。