【React】react-transition-groupを使ってCSSのアニメーションを実装する

f:id:utr066:20180811223617j:plain

reactを使ってアニメーションをさせたいなんて時もあるのではないでしょうか。日本語のものがそこまでないのがちょっと残念ですが、それでも探してみればライブラリは色々あります。

今回は、react-transition-groupというものを使ってCSSのアニメーションを実装していきたいと思う。

react-transition-groupを使う

github.com

<CSSTransition></CSSTransiton>で囲うことによって囲ったものに対してCSSアニメーションを設定することができる。

<CSSTransiton>classNamesを指定することによって、以下のクラスが適用されるようになる。

  • enter
  • enter-active
  • enter-active-done
  • exit
  • exit-active
  • exit-done
  • appear
  • appear-active

例えば、<CSSTransition classNames="fade">のようにすると以下のようなクラスが適用されます。

  • fade-enter(追加時)
  • fade-enter-active(追加中)
  • fade-enter-done(追加完了?)
  • fade-exit(削除時)
  • fade-exit-active(削除中)
  • fade-exit-done(削除完了?)
  • fade-appear(マウント時)
  • fade-appear-active(マウント中)

自動的に設定されたくない場合は、以下のように詳細に設定することも可能です。

classNames={{
 appear: 'my-appear',
 appearActive: 'my-active-appear',
 enter: 'my-enter',
 enterActive: 'my-active-enter',
 enterDone: 'my-done-enter,
 exit: 'my-exit',
 exitActive: 'my-active-exit',
 exitDone: 'my-done-exit,
}}

文字の追加時にアニメーションを行う

f:id:utr066:20180811223838j:plain 以下を使ってアニメーションを実行したいと思います。

  • enter
  • enter-active
  • exit
  • exit-active

文字を入力し、その文字が表示された時と削除時ににアニメーションさせたいと思います。

When the in prop is toggled to true the Component will get the example-enter CSS class and the example-enter-active CSS class added in the next tick. This is a convention based on the classNames prop.

inというものを使って、それがtrueに変わった時にしかenterenter-activeは使えないようです。なので、stateのtrueとfalseを入力する毎に入れ替えて、文字が入力されるたびにアニメーションさせたいと思います。

import React from 'react';
import ReactDOM from 'react-dom';
import { CSSTransition } from 'react-transition-group';
import './styles.css';

class Example extends React.Component {
  constructor(props){
    super(props);
    this.state = ({
      name: "",
      judge: false
    });
  }

  handleChange(name) {
    this.setState({
       name: name,
       judge: !this.state.judge
    });
  }

  render() {
    return(
      <div>
        <input type="text" onChange={ e => this.handleChange(e.target.value)}></input>
        <CSSTransition
         in={this.state.judge}
         classNames="input"
         >
          <p>{ this.state.name }</p>
        </CSSTransition>
      </div>
    );
  }
}

ReactDOM.render(
  <Example />,
  document.getElementById('root')
);
.input-enter {
  opacity: 0.1;
  transform: scale(0.9) translateY(50%);
}
.input-enter-active {
  opacity: 1;
  transform: scale(1) translateY(0%);
  transition: all 300ms ease-out;
}
.input-exit {
  opacity: 1;
  transform: scale(1) translateY(0%);
}
.input-exit-active {
  opacity: 0.1;
  transform: scale(0.9) translateY(50%);
  transition: all 300ms ease-out;
}

これを実行してみると以下のような感じになります。

hogehogereact.gif

文字が入力されるたびに文字が出たり消えたりしていますね。ただ、ちょっとこれではcssの反映が分かりにくいので、enter時とexit時の動作を色付きで確認してみます。

cssを以下のようにして、再度確認してみましょう。background-colorで赤と緑を指定したので、文字の追加時に赤から緑に色が変わるはずです。

.input-enter {
  opacity: 0.1;
  background-color: red;
  transform: scale(0.9) translateY(50%);
}

.input-enter-active {
  opacity: 0.7;
  background-color: green;
  transform: scale(1) translateY(0%);
  transition: all 300ms ease-out;
}

changecolorreact.gif

文字を入力すると背景色が変わるのが確認できますね。

文字を削除した時の挙動も確認しておきましょう。文字を削除する時に背景色を黒から黄色に変えるとします。

.input-exit {
  opacity: 0.7;
  background-color: black;
  transform: scale(1) translateY(0%);
}

.input-exit-active {
  opacity: 0.1;
  background-color: yellow;  
  transform: scale(0.9) translateY(50%);
  transition: all 300ms ease-out;
}

changecolorreact2.gif

こっちも一瞬ですが黒から黄色になっていますね。 組み合わせるとこんな感じになります。

rotatecolorreact.gif

マウント時にcssを追加する

f:id:utr066:20180811224209j:plain マウント時に動作するのは以下です。

  • appear
  • appear-active

propsにtrueのinappearが必要なので渡しておきます。

<CSSTransition
  in
  classNames="hoge"
  appear={true}
>
  <p>hoge</p>
</CSSTransition>
.hoge-appear {
  opacity: 0.4;  
  background-color: black;
}

.hoge-appear-active {
  opacity: 0.9;  
  background-color: yellow;
  transition: opacity 500ms ease-in;
}

reactmount.gif

色が表示されますね。

doneの使い道

enter-doneやexit-doneの使い道が正直よく分からない。https://github.com/reactjs/react-transition-groupのCSSTransition.jsでインポートしているTransition.jsの中でIn the context of a TransitionGroup all enters are really appearsとコメントがなされているが、これは・・・実際は、全てappearsになるような想定なのだろうか。