[ReactTransitionGroup]ハンズオン！モーダルアニメーションを実装する！

ReactでCSSアニメーションを扱うためのライブラリを紹介していきます。

## React-transition-groupとは

アニメーションそのものを提供しているのではなく、CSSをDOMに反映するタイミングを管理してアニメーションを実現するライブラリとなっています。そして4つのコンポーネントが用意されています。

- Transition
- CSSTransition
- SwitchTransition
- TransitionGroup

作りたいアニメーションによって使い分ける必要があります。

[公式](https://reactcommunity.org/react-transition-group)

## インストール

```
# npm
npm install react-transition-group

# yarn
yarn add react-transition-group
```

## モーダルを実装
今回はCSSTransitionとStyledComponentを用いてモーダルを実装します。

実際の挙動がこちらです。

![modal.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/742770/d079c15a-4fd3-eb86-7ecb-5eae65307b7f.gif)

このモーダルのアニメーションはオーバーレイとモーダル本体の２つで構成されています。オーバーレイはフェードインとフェードアウト、一方モーダル本体はフェードインとフェードアウトに加え拡大縮小が含まれています。

それではコードを見ていきましょう。

```tsx
import './App.css';
import {CSSTransition} from "react-transition-group";
import {useState} from "react";
import styled from "styled-components";

export const App = () => {
  const [isOpen, switchIsOpen] = useState(false)

  return (
    <>
      <TransitionStyle>
        <div className="open" onClick={() => switchIsOpen(true)}>開く</div>
        <div className="modal-wrapper">
          <CSSTransition
            classNames="modal"
            in={isOpen}
            timeout={700}
            unmountOnExit>
            <ModalStyle>
              <div className="content">
                モーダルです。
              </div>
              <div className="close" onClick={() => switchIsOpen(false)}>閉じる</div>
            </ModalStyle>
          </CSSTransition>
        </div>
        <CSSTransition
          classNames="overlay"
          in={isOpen}
          timeout={700}
          unmountOnExit>
          <OverlayStyle/>
        </CSSTransition>
      </TransitionStyle>
    </>
  );
}

export default App

// transitionのスタイル
const TransitionStyle = styled.div`
  .open{
    cursor: pointer;
    font-size: 40px;  
    font-weight: bold;
  }
  
  .modal-wrapper{
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    
    .modal-enter {
      opacity: 0;
      transform: scale(0.9);
    }

    .modal-enter-active {
      opacity: 1;
      transform: translateX(0);
      transition: opacity 0.3s, transform 0.3s;
    }

    .modal-exit {
      opacity: 1;
    }

    .modal-exit-active {
      opacity: 0;
      transition: opacity 0.3s, transform 0.3s;
      transform: scale(0.9);
    }
  }
  
  .overlay-enter {
    opacity: 0;
  }

  .overlay-enter-active {
    opacity: 1;
    transform: translateX(0);
    transition: opacity 0.3s, transform 0.3s;
  }

  .overlay-exit {
    opacity: 1;
  }

  .overlay-exit-active {
    opacity: 0;
    transition: opacity 0.3s, transform 0.3s;
  }
`;

// モーダルのスタイル
const ModalStyle = styled.div`
  padding: 100px;
  background-color: #ffffff;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  
  .content{
    font-size: 40px;
    font-weight: bold;
  }
  
  .close{
    cursor: pointer;
    margin: 50px 0 0;
  }
`

// オーバーレイのスタイル
const OverlayStyle = styled.div`
  display: flex;
  align-items: center;
  justify-content: center;
  position: fixed;
  z-index: -1;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
`;
```
オーバーレイとモーダル本体で使用したCSSTransitionのプロパティは同じなので、モーダル本体を例に挙げ解説します。

inは表示非表示を切り替えるためのステートを渡します。

timeoutはアニメーションの開始から終了までの時間です。

最後のunmountOnExitはアニメーションが終了した時にCSSTransitionをアンマウントさせることができます。

そしてCSSTransitionにchildrenで渡しているのがモーダル本体です。オーバーレイも同様です。

```tsx
<CSSTransition
  classNames="modal"
  in={isOpen}
  timeout={700}
  unmountOnExit>
  <ModalStyle>
    <div className="content">
      モーダルです。
    </div>
    <div className="close" onClick={() => switchIsOpen(false)}>閉じる</div>
  </ModalStyle>
</CSSTransition>
```

classNamesに渡した文字列が、アニメーションのクラス名のプレフィックスになります。

```tsx
例
classNames="modal"

アニメーション開始時のクラス名="modal-enter"
アニメーション中のクラス名="modal-enter-active"
アニメーション終了時のクラス名="modal-exit"
アニメーション中のクラス名="modal-exit-active"
```
上記のクラス名を使用したコードです。

```tsx
.modal-enter {
  opacity: 0;
  transform: scale(0.9);
}

.modal-enter-active {
  opacity: 1;
  transform: translateX(0);
  transition: opacity 0.3s, transform 0.3s;
}

.modal-exit {
  opacity: 1;
}

.modal-exit-active {
  opacity: 0;
  transition: opacity 0.3s, transform 0.3s;
  transform: scale(0.9);
}
```
モーダルの切り替えステートをtrueにするとmodal-enterのスタイルでマウントされ、modal-enter-activeのスタイルに切り替わります。   
falseにするとmodal-exitのスタイルが適応され、modal-exit-activeに切り替わりアンマウントされるという流れになります。

## まとめ
モーダル以外にも他のコンポーネントを用いて様々な動きのアニメーションを実装することができます。自分でcssを書いて実装するため柔軟性の高いアニメーションを作ることができます。ぜひ使ってみてはいかがでしょうか。