26
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ScrollRevealを使ってNextJS(React)でスクロールアニメーションを簡単に実装する方法

Posted at

#はじめに
フロントエンドでReactやNextJSを使用しているときにスクロールアニメーションをコンポーネント化して簡単に使用する方法を見つけたので、共有します。

#スクロールアニメーションを実装する

アプリケーションやWebサイトを作成する時にアニメーションがあったりすると途端に本格的に見えたりしますが、CSSで実装するのは中々面倒だったりします。
今回紹介するのは「scrollreveal」というライブラリとReactを使用して再利用性の高いアニメーションコンポーネントを作成していきたいと思います。

##ScrollReveal
ScrollRevealはJavascriptでスクロールアニメーションが実装できるようになるライブラリで、よくWebサイトで見る「スクロールしたらふわっと出てくる」アニメーション効果を与えてくれます。
公式ドキュメント

使用するには、scriptタグで読み込むかnpm(yarn)でライブラリをインストールします。

//scriptで読み込み
<script src="https://unpkg.com/scrollreveal"></script>
//npm(yarn)でインストール
npm i -S (yarn add) scrollreveal

typescriptを使用している方は、別途型定義ファイルも必要なので、インストールします。

npm i -S -D(yarn add -D) @types/scrollreveal

アニメーション効果をつけるにはScrollReveal().reveal()メソッドで対象のclass等を指定すれば、簡単にアニメーション効果をつけることができます。

//第二引数で効果時間の設定等が可能。詳しくは公式ドキュメントを参照して下さい
ScrollReveal().reveal('.container', {
 duration: 500,
 reset: true
})

##Reactでコンポーネント化
次にReactで要素をラップすればアニメーション効果を付与できるコンポーネントを作成します。

ScrollRevealContainer.tsx
import { FC, useRef, useEffect } from "react";
import scrollReveal from "scrollreveal";

interface ScrollRevealContainerProps {
  move?: string;
}

const ScrollRevealContainer: FC<ScrollRevealContainerProps> = ({
  children,
  move
}) => {
  const sectionRef = useRef<HTMLElement>(null);

  useEffect(() => {
    if (sectionRef.current)
      scrollReveal().reveal(sectionRef.current, {
        reset: true,
        delay: 400,
        opacity: 0,
        origin:
          move === "left"
            ? "left"
            : move === "right"
            ? "right"
            : move === "top"
            ? "top"
            : "bottom",
        distance: "40px"
      });
  }, [sectionRef]);

  return <section ref={sectionRef}>{children}</section>;
};
export default ScrollRevealContainer;

このコンポーネントではReactのuseRef,useEffectを用いてアニメーション発動のタイミングを設定しています。
まずuseRefでこのコンポーネントまでスクロールした時にDOMを参照し、useEffectでDOMが参照される度にscrollrevealのメソッドを実行するようにします。
また任意でpropsを渡せるようにしており、left,right,top,bottomの中から渡した値の方向からコンポーネントがスクロールして表れるようにしています(何もpropsを渡さなければ下部から表れます)。

あとはアニメーションを実装したい要素をこのコンポーネントで囲むだけです。

app.tsx

import ScrollRevealContainer from "./ScrollRevealContainer";

export default function App() {
  return (
    <>
      <div style={{ marginBottom: "400px" }}></div>
      <ScrollRevealContainer move="right">
        <h1>右から登場</h1>
        <h2>Edit to see some magic happen!</h2>
      </ScrollRevealContainer>
      <ScrollRevealContainer move="left">
        <h1>左から登場</h1>
        <h2>Edit to see some magic happen!</h2>
      </ScrollRevealContainer>
      <ScrollRevealContainer move="top">
        <h1>上から登場</h1>
        <h2>Edit to see some magic happen!</h2>
      </ScrollRevealContainer>
      {/* ↓props「move」に何も指定しなければ「origin」は「bottom」になる */}
      <ScrollRevealContainer>
        <h1>下から登場</h1>
        <h2>Edit to see some magic happen!</h2>
      </ScrollRevealContainer>
    </>
  );
}

このように要素をScrollRevealContainerコンポーネントで囲むだけで簡単に実装できました!
実際にはこのように動作するので確認してみて下さい↓
Code Sandbox

##NextJSで使用する際の注意点

Reactでは上記の方法で動作するのですが、同じ方法をNextJSで実装するとdocument is not defindというエラーが表示されます。
これはレンダリング方法の違いによって起こるものであり、NextJSは開発モード時デフォルトでSSR(Server Side Rendering)でレンダリングされるのですが、サーバーサイドに存在しないdocumentを参照しているためにこのようなエラーが発生します。
解決方法としてはnext/dynamicを使用してコンポーネントを動的インポートし、さらにオプションssr:falseを指定して対象のコンポーネントをSSRさせないようにすればOKです。

app.tsx
//動的インポートを使用し、オプションでSSRさせないよう設定
const ScrollRevealContainer = dynamic(
	import('./ScrollRevealContainer'),
	{ssr: false,}
);

こうすればエラーが解消されます!

参考:Next.jsでwindow is not definedを解決する(依存ライブラリ対応)

#まとめ

React(NextJS)を使用して再利用性の高いアニメーションコンポーネントで作成できました。
今後も新しい情報が入り次第随時更新していきます。

26
20
2

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
26
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?