ReactはアニメーションのためにローレベルAPIとして ReactTransitionGroup アドオンコンポーネントと、基本的なCSSアニメーションとトランジションを簡単に実行するために ReactCSSTransitionGroup を提供しています。
ReactCSSTransitionGroup #ReactCSSTransitionGroup は ReactTransitionGroup に基づいており、ReactコンポーネントがDOMを作成したり、削除したりする際に、CSSのトランジションとアニメーションを行う簡単な方法です。これは、素晴らしいng-animateライブラリにインスパイアされています。
ReactCSSTransitionGroup は ReactTransitions のインターフェースです。アニメーションに関心がある全てのコンポーネントをラップする単純な要素です。以下が、リストのアイテムをフェードインやフェードアウトさせる例です。
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
var TodoList = React.createClass({
getInitialState: function() {
return {items: ['hello', 'world', 'click', 'me']};
},
handleAdd: function() {
var newItems =
this.state.items.concat([prompt('Enter some text')]);
this.setState({items: newItems});
},
handleRemove: function(i) {
var newItems = this.state.items;
newItems.splice(i, 1);
this.setState({items: newItems});
},
render: function() {
var items = this.state.items.map(function(item, i) {
return (
<div key={item} onClick={this.handleRemove.bind(this, i)}>
{item}
</div>
);
}.bind(this));
return (
<div>
<button onClick={this.handleAdd}>Add Item</button>
<ReactCSSTransitionGroup transitionName="example">
{items}
</ReactCSSTransitionGroup>
</div>
);
}
});
注意: もし子要素を1つだけレンダリングするとしても、
ReactCSSTransitionGroupの全ての子要素に提供しなければなりません。これが、Reactが、子要素が作成されているか、削除されたか、あるいはそのままであるか判断する方法です。
このコンポーネントでは、 ReactCSSTransitionGroup に新しいアイテムが追加された次の瞬間に、 example-enter CSSクラスと example-enter-active CSSクラスを得ます。これは、 transitionName propに基づく習慣です。
これらのクラスはCSSアニメーションやトランジションのトリガーとして使うことができます。例えば、以下のようにして、このCSSを加え、新しいリストアイテムを加えてみましょう。
.example-enter {
opacity: 0.01;
transition: opacity .5s ease-in;
}
.example-enter.example-enter-active {
opacity: 1;
}
アイテムを削除しようとしたときに、 ReactCSSTransitionGroup がDOMの中にそれを保持していることに気づくでしょう。縮小化されていないReactのビルドとアドオンを使っているならば、Reactがアニメーションやトランジションが起こることを予期しているという警告が出るでしょう。これは、 ReactCSSTransitionGroup がアニメーションが終わるまでDOM要素をページに保持し続けるからです。以下のCSSを加えてみましょう。
.example-leave {
opacity: 1;
transition: opacity .5s ease-in;
}
.example-leave.example-leave-active {
opacity: 0.01;
}
ReactCSSTransitionGroup は transitionAppear というオプションのプロパティを提供します。コンポーネントの最初のマウントの際に、更なるトランジションのフェーズを加えるためです。一般的には、 transitionAppear が false である最初のマウントの際にはトランジションのフェーズはありません。 transitionAppear プロパティを値が true である状態で渡す以下の例を見てみましょう。
render: function() {
return (
<ReactCSSTransitionGroup transitionName="example" transitionAppear={true}>
<h1>Fading at Initial Mount</h1>
</ReactCSSTransitionGroup>
);
}
最初のマウントの間、 ReactCSSTransitionGroup は example-appear CSSクラスを得て、次の瞬間に example-appear-active CSSクラスを加えます。
.example-appear {
opacity: 0.01;
transition: opacity .5s ease-in;
}
.example-appear.example-appear-active {
opacity: 1;
}
最初のマウントの際には、 ReactCSSTransitionGroup の全ての子要素は appear しますが、 enter はしません。一方、存在する ReactCSSTransitionGroup に後から加えられた子要素は全て enter しますが、 appear はしません。
注意:
transitionAppearプロパティはバージョン0.13でReactCSSTransitionGroupに加えられました。後方互換性を維持するために、デフォルトの値はfalseに指定されています。
子要素にトランジションを適用するためには、 ReactCSSTransitionGroup はすでにDOMにマウントされているか、 transitionAppear プロパティに true がセットされている必要があります。以下の例は動きません。 ReactCSSTransitionGroup が新しいアイテムとともにマウントされており、新しいマウントがマウントされていないからです。これと上のはじめに とで違いを比較してみてください。
render: function() {
var items = this.state.items.map(function(item, i) {
return (
<div key={item} onClick={this.handleRemove.bind(this, i)}>
<ReactCSSTransitionGroup transitionName="example">
{item}
</ReactCSSTransitionGroup>
</div>
);
}, this);
return (
<div>
<button onClick={this.handleAdd}>Add Item</button>
{items}
</div>
);
}
上の例では、 ReactCSSTransitionGroup にアイテムのリストをレンダリングしました。しかし、 ReactCSSTransitionGroup の子要素は1個や0個のアイテムになり得ます。単一の要素が作成や削除のアニメーションを可能にします。同様に、現在の要素を置き換える新しい要素をアニメーションできます。例えば、以下のように、1つの画像でカルーセルを実行できます。
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
var ImageCarousel = React.createClass({
propTypes: {
imageSrc: React.PropTypes.string.isRequired
},
render: function() {
return (
<div>
<ReactCSSTransitionGroup transitionName="carousel">
<img src={this.props.imageSrc} key={this.props.imageSrc} />
</ReactCSSTransitionGroup>
</div>
);
}
});
もししたいならば、 enter や leave のアニメーションを無効にすることもできます。例えば、 enter アニメーションは行いたいが、 leave のアニメーションは行いたくない場合があるでしょう。しかし、 ReactCSSTransitionGroup はDOMのノードが削除される前にアニメーションが終わるのを待ちます。ReactCSSTransitionGroup がそれらのアニメーションを無効化するために、 transitionEnter={false} や transitionLeave={false} といったプロパティを追加することができます。
注意:
ReactCSSTransitionGroupを使う際には、コンポーネントがトランジションが終わったことを検知したり、アニメーション関連でさらに複雑なロジックを実行するといったことはできません。更に細かな制御を求める場合は、トランジションをカスタムするために必要なフックを提供するローレベルのReactTransitionGroupAPIを使用できます。
ReactTransitionGroup #ReactTransitionGroup はアニメーションの基盤です。 React.addons.TransitionGroup と同じくらい簡単に使用できます。これによって(上記の例のように)、宣言的に子要素が追加されたり削除されたりするときに、それらの上で特別なライフサイクルのフックが呼ばれます。
componentWillAppear(callback) #このメソッドは TransitionGroup の中で最初にマウントされるコンポーネントのために componentDidMount() と同時に呼ばれます。これは、 callback が呼ばれるまで、他のアニメーションが発生するのをブロックします。これは、 TransitionGroup の最初のレンダリングのときにのみ呼ばれます。
componentDidAppear() #componentWillAppear が呼ばれて渡される callback 関数の後に呼ばれます。
componentWillEnter(callback) #これは、存在する TransitionGroup に追加されるコンポーネントのために、 componentDidMount() と同時に呼ばれます。これは、 callback が呼ばれるまで、他のアニメーションが発生するのをブロックします。これは、 TransitionGroup の最初のレンダリングのときには呼ばれません。
componentDidEnter() #componentWillEnter が呼ばれて渡される callback 関数の後に呼ばれます。
componentWillLeave(callback) #これは、 ReactTransitionGroup から子要素が削除されたときに呼ばれます。子要素が削除されても、 ReactTransitionGroup は callback が呼ばれるまでDOMの中に子要素を保持し続けます。
componentDidLeave() #これは、 willLeave の callback が呼ばれた際に呼ばれます( componentWillUnmount と同時です)。
デフォルトで、 ReactTransitionGroup は span としてレンダリングされます。この動きは、 component プロパティによって変更できます。例えば、 <ul> をレンダリングしたい場合は以下のようになります。
<ReactTransitionGroup component="ul">
...
</ReactTransitionGroup>
Reactがレンダリングできる全てのDOMコンポーネントが使用できます。しかし、 component はDOMコンポーネントである必要はありません。あなたが求めているどんなReactのコンポーネントにもなり得ます。あなた自身が記述したものにもです!
注意: v0.12以前では、DOMのコンポーネントを使用する際には、
componentプロパティがReact.DOM.*を参照している必要がありました。コンポーネントが単純にReact.createElementから渡されていたからです。これは今は文字列である必要があります。複合的なコンポーネントは複合的なものを渡す必要があります。
全ての付加的な、ユーザー定義のプロパティはレンダリングされたコンポーネントのプロパティになります。例えば、以下はCSSクラスとともに <ul> をレンダリングする方法です。
<ReactTransitionGroup component="ul" className="animated-list">
...
</ReactTransitionGroup>