🫥

【React】CSS Modules + CSSTransitionを使ってtransition単位でアニメーションを実装する

2023/04/23に公開

背景

業務の中でreact-transtion-groupCSSTrantionCSSModulesで実装する方法を調査しました。

実装方法がなかなか見つからなかったので、備忘録として残しておきます。

実装方法

準備

ボタンをクリックした時に、アニメーションさせるような実装を簡単に書いてみます

src/App.js
import styles from './App.module.scss';
import { CSSTransition } from 'react-transition-group';
import { useState } from 'react';

function App() {

  // 表示、非表示用のstate
  const [inProp, setInProp] = useState(false)

  return (
    <div className={styles.container}>
      <div className={styles['animation-content']}>Fade Animation</div>
      <div className={styles['button-content']}>
        <button onClick={() => {
          setInProp(!inProp)
        }}>
          クリック
        </button>
      </div>
    </div>
  )
}

export default App;

(一応、scssも記述します)

src/App.module.scss
.container {
    width: 100%;
    height: 80vh;
    justify-content: center;
    align-items: center;

    .animation-content {
        background: orange;
        border-radius: 20px;
        margin: 200px auto 0;
        width: 200px;
        height: 200px;
        text-align: center;
        line-height: 200px;
        font-size: 20px;
        color: white;
    }

    .button-content {
        margin-top: 20px;
        text-align: center;
    }
}

上記の実装で見た目はこんな感じになっています。

ライブラリのインストール

react-transition-groupを追加します。

npm install react-transition-group --save

アニメーション追加

fadeのアニメーションを追加していきます。

まず、fade用のCSSmodulesファイルを準備します。

src/styles/transitions/fade.module.scss
// 表示時アニメーション開始時の状態
.enter {
    opacity: 1;
}

// 表示時アニメーション中の状態
.enterActive {
    opacity: 0;
    transition: opacity 500ms;
}

// 表示時アニメーション終了時の状態
.enterDone {
    opacity: 0;
}

// 非表示アニメーション開始時の状態
.exit {
    opacity: 0;
}

// 非表示アニメーション中の状態
.exitActive {
    opacity: 1;
    transition: opacity 500ms;
}

// 非表示アニメーション終了時の状態
.exitDone {
    opacity: 1;
}

app.jsCSSTransitionを追加していきます。

src/App.js
import styles from './App.module.scss';
import fade from './styles/transitions/fade.module.scss';
import { CSSTransition } from 'react-transition-group';
import { useState, useRef } from 'react';

function App() {

  const [inProp, setInProp] = useState(false)
  const nodeRef = useRef(null)

  return (

    <div className={styles.container}>
      {/* ↓ fade用のstylesを設定 */}
      <CSSTransition in={inProp} timeout={500} classNames={fade} nodeRef={nodeRef}>
        <div className={styles['animation-content']} ref={nodeRef}>Fade Animation</div>
      </CSSTransition>
      <div className={styles['button-content']}>
        <button onClick={() => {
          setInProp(!inProp)
        }}>
          クリック
        </button>
      </div>
    </div>
  )
}

export default App;

CSSTransitionで設定しているプロパティとしては、下記の通りです。

in: 表示、非表示を切り替えるためのstateを設定
timeout: アニメーションが完了するまでの時間を設定
classNames: アニメーション用のスタイルを設定

classNamesでfadeを設定することで、fadeで設定したclassNameが展開されて、

classNames={{
 enter,
 enterActive,
 enterDone,
 exit,
 exitActive,
 exitDone,
}}

のようにアニメーションに必要なclassNameが設定されます。

結果

実際にアニメーションを動作させてみます。

うまくfadeアニメーションが実装されていることを確認できました!

追記

  • CSSTransitionにnodeRefがついてない
  • classNameがclassになっている

のミスがあったので、修正しました💦(2023/05/11)

Discussion