React.jsのCSSアニメーション
公式ドキュメント: https://facebook.github.io/react/docs/animation.html
参考: http://qiita.com/koba04/items/236014c955f8af14d3fc
追加されたり削除されたりした際にCSS Transition等を使ってアニメーションが出来るようにしたいとかまぁあるあるパターンだと思いますが、そういうのもサポートされてる模様
動作の概要のキャプチャ動画
{% youtube DVcBfxiMTOk %}
CSSTransitionGroupを使った場合
var React = require("react/addons"),
CSSTransitionGroup = React.addons.CSSTransitionGroup;
var Top = React.createClass({
mixins: [React.addons.LinkedStateMixin],
getInitialState: function() {
return { items: [] };
},
render: function() {
var items = this.state.items.map(function(item, i) {
var key = "ITEM" + (i + 1);
return (
<div key={key} className="item">
{item}
<button onClick={this.onDelete.bind(this, i)}>x</button>
</div>
);
}.bind(this));
return (
<div>
<input type="text" valueLink={this.linkState("text")} />
<button onClick={this.onClick}>send</button>
<div>
<CSSTransitionGroup transitionName="item">
{items}
</CSSTransitionGroup>
</div>
</div>
);
},
onClick: function(e) {
e.preventDefault();
var items = this.state.items;
items.push(this.state.text);
this.setState({ items: items, text: "" });
},
onDelete: function(i, e) {
var items = this.state.items;
delete items[i];
this.setState(items);
}
});
React.render(
<Top />,
document.querySelector("#app")
);
っていう感じでCSSTransitionGroupを使えばtransitionNameで指定した値に対応するCSSが作用するようになる。例えば以下の様な感じのCSS作れば良い
.item-enter {
-webkit-transition: 1s ease-in;
opacity: 0;
}
.item-enter-active {
opacity: 1;
}
.item-leave {
-webkit-transition: 1s ease-in;
opacity: 1;
}
.item-leave-active {
opacity: 0;
}
TransitionGroupを使った場合
CSSTransitionGroupとは違いイベントをReactコンポーネント側で管理する方法も取れる
var React = require("react/addons"),
TransitionGroup = React.addons.TransitionGroup,
$ = require("jquery");
var Item = React.createClass({
propTypes: {
text: React.PropTypes.string
},
componentWillEnter: function(callback) {
$(this.getDOMNode()).css("opacity", "0");
callback();
},
componentDidEnter: function() {
$(this.getDOMNode()).animate({ opacity: 1 }, { duration: 2000 });
},
componentWillLeave: function(callback) {
$(this.getDOMNode()).animate({ opacity: 0 }, { duration: 2000 }, callback);
},
componentDidLeave: function() {
},
render: function() {
var text = this.props.text;
return (
<div className="item">
{text}
<button onClick={this.props.onDelete}>x</button>
</div>
);
}
});
var Items = React.createClass({
getInitialState: function() {
return { items: [] };
},
render: function() {
var items = this.state.items.map(function(data, i) {
var key = "ITEM" + (i + 1);
return (
<Item key={key} text={data} onDelete={this.onDelete.bind(this, i)} />
);
}.bind(this));
return (
<div>
<TransitionGroup component="div">
{items}
</TransitionGroup>
</div>
);
},
addItem: function(item) {
if (item) {
var items = this.state.items;
items.push(item);
this.setState({ items: items });
}
},
onDelete: function(i, e) {
e.preventDefault();
var items = this.state.items;
delete items[i];
this.setState(items);
}
});
var Top = React.createClass({
mixins: [React.addons.LinkedStateMixin],
getInitialState: function() {
return { text: "" };
},
render: function() {
return (
<div>
<input type="text" valueLink={this.linkState("text")} />
<button onClick={this.onClick}>send</button>
<Items ref="items" />
</div>
);
},
onClick: function(e) {
e.preventDefault();
if (this.state.text) {
this.refs.items.addItem(this.state.text);
this.setState({ text: "" });
}
}
});
React.render(
<Top />,
document.querySelector("#app")
);
っていうようにcomponentWillEnter/componentDidEnter/componentWillLeave/componentDidLeaveなイベントメソッドが作用するようになる
まぁざっくりとして使ってみただけなんだけど、詳しくはドキュメントか参考読むと良い。とりあえずハマるのはkeyを持つ場所をミスるとイベントが正しく作用しなかったりする