今回はReact.jsでのAnimationについて書きたいと思います。
React.jsではAddonとしてサポートされていて、CSS Animationを使ったCSSTransitionGroupとComponentのLifecycle MethodのようにMethodでフックして書く2パターンあります。
CSSTransitionGroup
こちらではComponentの追加・削除時にCSSアニメーションさせることが出来ます。やりかたはAngular.jsやvue.jsのものに近くて追加・削除時にclassが追加されるのでcssにアニメーションを記述する感じです。
{transitionName}-{enter,leave}
のclassName
追加された後、次のイベントループで{transitionName}-{enter,leave}-active
のclassName
が追加されるので、追加されるclassName
を使ってCSSアニメーションを書いていきます。
var CSSTransitionGroup = React.addons.CSSTransitionGroup;
var Hello = React.createClass({
getInitialState: function() {
return {
value: '(´・ω・`)'
};
},
onClick: function() {
var value = this.state.value === '(´・ω・`)' ? '(`・ω・´)ゞ' : '(´・ω・`)';
this.setState({ value: value });
},
render: function() {
var value = <span className="sample" key={this.state.value}>{this.state.value}</span>;
return (
<div>
<div>Animation!!<button onClick={this.onClick}>click!!</button></div>
<CSSTransitionGroup transitionName="sample">
{value}
</CSSTransitionGroup>
</div>
);
}
});
React.render(<Hello />, document.body);
.sample-enter {
-webkit-transition: 1s ease-in;
}
.sample-enter.sample-enter-active {
font-size: 80px;
}
.sample-leave {
-webkit-transition: .5s ease-out;
}
.sample-leave.sample-leave-active {
font-size: 10px;
}
注意点
-
アニメーションさせる要素には必ず
key
を指定する必要があります。アニメーションさせる要素が1つの場合でも必ずつける必要があります。これはComponentが追加されたのか更新されたのかを明確に示すためだと思います。- これを利用すると、上記の例のように1つのComponentでも
key
を変化させることでアニメーションさせることが可能になります。(Componentの追加・削除が行われるので)
- これを利用すると、上記の例のように1つのComponentでも
-
アニメーションは追加時(enter)と削除時(leave)の両方に指定する必要があります。
- 追加時、削除時だけにアニメーションさせたい場合は
transitionEnter={false}
やtransitionLeave={false}
を指定することが出来ます。
- 追加時、削除時だけにアニメーションさせたい場合は
<CSSTransitionGroup transitionName="sample" transitionLeave={false}>
{value}
</CSSTransitionGroup>
- CSSTransitionGroupのComponentはアニメーション開始時にはrenderingされている必要があって、追加される要素と一緒にCSSTransitionGroupのComponentを追加してもアニメーションしません。
↓の場合は、1回目のclickではCSSTransitionGroup
がないためアニメーションしない
var Hello = React.createClass({
getInitialState: function() {
return {
value: ''
};
},
onClick: function() {
var value = this.state.value === '(´・ω・`)' ? '(`・ω・´)ゞ' : '(´・ω・`)';
this.setState({ value: value });
},
render: function() {
var value ;
if (this.state.value) {
value = (
<CSSTransitionGroup transitionName="sample">
<span className="sample" key={this.state.value}>{this.state.value}</span>
</CSSTransitionGroup>
);
}
return (
<div>
<div>Animation!!<button onClick={this.onClick}>click!!</button></div>
{value}
</div>
);
}
});
ReactTransitionGroup
CSSアニメーションではなくて自分で柔軟に処理を書きたい場合は、ReactTransitionGroupを使うことが出来ます。
componentWillEnter(callback)
、componentDidEnter()
、componentWillLeave(callback)
、componentDidLeave()
という4つのメソッドがLifecycleに応じて呼ばれるようになるので実装します。
またReactTransitionGroupはdefaultだとspan要素としてDOMに追加されるのですが、<ReactTransitionGroup component="ul">
などとすることで要素を指定することが出来ます。
var TransitionGroup = React.addons.TransitionGroup;
var duration = 1000;
var AnimationComponent = React.createClass({
componentWillEnter: function(callback) {
console.log("component will enter");
$(this.getDOMNode()).hide();
callback();
},
componentDidEnter: function() {
$(this.getDOMNode()).show(duration);
console.log("component did enter");
},
componentWillLeave: function(callback) {
console.log("component will leave");
$(this.getDOMNode()).hide(duration, callback);
},
componentDidLeave: function() {
console.log("component did leave");
},
render: function() {
return <div>{this.props.text}</div>
}
});
var Hello = React.createClass({
getInitialState: function() {
return {
value: '(´・ω・`)'
};
},
onClick: function() {
var value = this.state.value === '(´・ω・`)' ? '(`・ω・´)ゞ' : '(´・ω・`)';
this.setState({ value: value });
},
render: function() {
var value = <AnimationComponent key={this.state.value} text={this.state.value} />;
return (
<div>
<div>Animation!!<button onClick={this.onClick}>click!!</button></div>
<TransitionGroup>
{value}
</TransitionGroup>
</div>
);
}
});
React.render(<Hello />, document.body);
注意点
-
componentWillEnter
とcomponentWillLeave
は処理が終わったら必ずcallback
を呼ぶ必要があります。
というわけでアニメーションについて簡単に説明しました。
アニメーション書くのに慣れてないせいかちょっと書きにくい感があって、今後の改善点にもAnimationは挙げられているのでもっとわかりやすく簡単に書けるようになるといいなと思っています。
明日はserver-side renderingについて書きたいと思います。