React、Next.jsでオープニングアニメーションを実装したい

17日目 ← 18日目 → 19日目

これはKCS Advent Calendar2022の18日目の記事です。

 

導入

こんにちは、かつおぶしです。

昨年はSOCDクリーナーという格ゲーのコントローラー制御を電子回路でやる、という内容の話を書いていました。

今年はWeb開発的な部分でオープニングアニメーションの制作について書いていきます。

 

動機:かっこいいオープニングアニメーションが作れたら、いいよね!!??

 

これだけです。

基本的にサイトに入ったときに演出が入ると、それだけでかなりアツいと思いませんか?

今自分は個人サイトを作っていて、そこにオープニングアニメーションがあったらいいなと思いました。ただ、自分にすごくWeb開発のスキルがあるわけではないので、これを機に勉強してみようというのが趣旨です。

参考文献のパクリにならない程度に昇華させたものを作りたいですが、多分これを読むよりも参考文献を読んだ方が百倍マシな気がしています。

 

環境

React

Next.js

Styled-components(選択)

上級者はこういうライブラリ使うとリッチに作れるかもです。

Framer-motion

React three fiber

 

Reactや各種パッケージを選んだ理由

Reactを選んだ理由

入口としてはReactという言語が流行っているため自分で学習したかったからです。これだけだとただのミーハーなので、ミーハーなりに良かったと思う点も列挙しておきます。

Web開発には様々な手段があり、サイト制作だけならWordpressやHTML・CSS・Javascriptの併用などでも問題ありませんが、Reactによる開発は体系的にコードを書くことができる点が非常にシンプルで評価できると感じています。

何が言いたいかといえば、コンポーネントベース最強、ということです。

Reactによる開発ではコンポーネントフォルダを作り、そこにパーツを作っておくことでApp.jsなどでこれをインポートし、コードを管理することができます。つまり、非常に綺麗に書けるわけです。ファイル分割の考え方も若干身に付きそうですし、いいんじゃないかな。

後はこのコンポーネントをベースにインタラクティブ(双方向)のサイト作りもすることが可能になります。Propsという概念を用いることでサイトに対してpropsを与えてサイトを更新する、ということができます。

Next.jsを選んだ理由

Next.jsによるサイト制作が楽だからです。

Next.jsはビルドする際、プリレンダリングから本レンダリングをすることでそのずれを修正しながらビルドをしています。これは公式のドキュメントを読めばもっと詳しくわかると思いますが、最初におおまかな木を作ることでビルド時間やSEOの最適化ができているそうです。

他にもnpm run devで仮想サーバーがリアルタイムで更新される点やエラー内容がそこで確認できるため、基本的にエディターとブラウザのみで開発ができ、リロード作業が少なくて済むというメリットがあります。

Styled-componentsを選んだ理由

後述する2番目の方法を使うときにインストールする必要があります。

Framer-motionを選んだ理由

Framer-motionはReact向けアニメーションパッケージです。

CSSによる簡易的なアニメーションよりも詳しいアニメーションを作成することが簡単で、これを使うことでインパクトのあるサイト作りができます。

後CSSでやってる記事が既にあったので被り防止というかちょっとのオリジナリティを出すために追加しました。

React three fiberを選んだ理由

React three fiberはReactでThree.jsというJavaScript向け3Dライブラリが使えるというもので、jsx(多分tsxでも書ける)でコーディングが可能になります。

この記事では自分の3D技術が足りないため、サイトに対しては何もしませんが、できる人はこういうの使うと多分かっこいいと思います。

 

作り方

基本的なBlogサイトなりをCloneしましょう

今回は大きく2つの方法を試したいと思います。

1つ目はReact標準のuseState, useEffectを用いる方法です。Loading状態を数秒間維持した後に解除するuseEffectを使います。これが解除された際に条件分岐でロード後に進む、というイメージです。

そして2つ目はstyled-componentsを用いてkeyframesを定義してコンポーネント化する方法です。これを使うと、ホーム画面をロード画面・メイン画面と連続して特別時間設定をすることなく行うことができます。こちらの方法の方がより詳しいアニメーション設定が行えるでしょう。(試してないですが、Framer-motionなどを使う場合もこっちの方がいい気がします)

1つ目の方法:useState, useEffect編

調べてみると、index.jsx(tsxでも可)のファイルの一部分を書き換える方法がありました。Loading中にアニメーションを実装しているように見せるため、通常時とLoading時を分けます。最初にサイトに飛んだ時にLoading状態として、そこからそのState(状態)を数秒間維持します。そのあと、Loading状態から通常状態に戻し、サイトを閲覧させる、という流れの記事がありました。ただ、useStateやuseEffectというReactにある機能を使って書き換えるという方法ですが、自分の使い方が悪いのか、エラーが出ました。

Error: Hydration failed because the initial UI does not match what was rendered on the server.

だそうです。調べてみるとエラーが出る場合は基本的にHTMLの書き方の都合でタグの入れ子構造に問題がある場合に出るエラーだそうです。useEffect周りでもこのエラーが出てしまう、という情報を得たので、それが原因かな、と思ったのですが、<Layout>タグを<Layout home>と修正したところエラーは改善されました。

これで行ったところ表示までの時間は伸びたため、これでおそらくアニメーションの実装はできるでしょう。ただ<Layout>タグに含まれる情報やサイト表現はすべてLoadingの条件分岐よりも前に書かれているため、Layoutに乗せる情報は少なくしましょう(後続する2つ目のアニメーションの場合でも同様です)。

pages/index.js

import {useState, useEffect} from 'react'
import Head from 'next/head'
const Home = () => {

    const [isLoading, setIsLoading] = useState(true)
useEffect(() => {
    setIsLoading(true)
    setTimeout(() => {
      setIsLoading(false);
    }, 2 * 1000)
  }, [])  

  return(
    <Layout home>
      <Head>
        <title>{siteTitle}</title>
      </Head>
      {isLoading ?
      <div>
         //Load中の処理
      </div>
      : <div>
         //Load後の処理
      </div>
      }
    </Layout>
  )
};
export default Home;

 

2つ目:コンポーネントにしてStyled-componentsを使う編

LoadingとMainpageの2つのコンポーネントを作成し、Loading、Mainpageをindex.jsに置いて、条件分岐等をせず一定の動作をさせるようにする方法でいきます。

ファイルの作り方としてはこんな感じです。

pages/index.js

import Head from 'next/head'
import Layout from '../components/layout.js'
import Loading from '../components/loading.js'
import Mainpage from '../components/mainpage.js'

const Home = () => {
   return(
      <Layout home>
         <Head>
            //サイトタイトルとか
         </Head>
         <Loading />
         <Mainpage />
      </Layout>
   );
};

components/loading.js

import styled, { keyframes } from 'styled-components';
const fadeIn = keyframes'
   0% {
      opacity: 0;
   }
   100% {
      opacity: 1;
   }
'
const Loading= () => {
   return (
      //ロード中の処理アニメーションを書く
   );
};

components/mainpage.js

import Intro from 'intro.js'  //インポートは一例
import Outro from 'outro.js'
import Gallary from 'gallary.js'
const mainpage = () => {
   return(
      <Intro />
      <Gallary />
      <Outro />
   )
}

Styled-componentsだけでもかなりの自由度でアニメーションが設定できますが、Framer-motionなどの外部パッケージを入れるとより高度なアニメーションが制作できるのでぜひ試してみてください(適当)。

 

終わりに

正直、雑な記事になってしまいましたが、ぜひこんな感じでサイトを作ってみてはいかがでしょうか。あけましておめでとうございます!!!

 

参考

Next.jsで「Error: Hydration failed because the initial UI…」のエラーが出た時の対処法

React (Next.js) のオープニングアニメーション

 

 

 

 

 

Posted on: 2023年1月4日, by : かつおぶし
Exit mobile version