こんにちは、山本です。
さて、React.jsの二回目です。
今回は、デザイナーさんにとってはとても重要らしいが、我々プログラマにとってはそこまで重要でもないもの。
そう、アニメーションをやってみようと思います。
ドキュメントを読む
さて、どのようにアニメーションを行うのでしょうか?
仮想DOMという考え方だと、アニメーションとはあまり相性は良くなさそうな印象ですが。
で気が付いたのですが、ReactはFacebook謹製というのに、前回はFacebookのドキュメントを殆ど見ていませんでした。
これは、反省すべき点ですね。
なので、今回はFacebookのドキュメントを見てましょう。
https://facebook.github.io/react/docs/animation.html
流石公式、すぐに見つかりました。
なんでも、ReactTransitionGroupという低レベルのものと、ReactCSSTransitionGroupという高レベルのものがあるそうですね。
初めから高レベルのものは求めていないので、低レベルものから初めます。
ReactTransitionGroupを使う
では、ReactTransitionGroupを使って、アニメーションを実装してみます。
ドキュメントを読むと、、、
ReactCSSTransitionGroupの事ばかりで、ReactTransitionGroupについての説明が全然ないですね。
検索しても、このページしか見つからないのでこの情報で進めていきます。
アニメーションはアドオンを使用するので、まずはreactとaddonを統合したスクリプトを読み込むようにします。
https://fb.me/react-with-addons-0.14.7.min.js
<!DOCTYPE html>
<html>
<head>
<script src="https://fb.me/react-with-addons-0.14.7.min.js"></script>
<script src="http://fb.me/JSXTransformer-0.13.3.js"></script>
</head>
<body>
<div id="container"></div>
<script type="text/jsx">
var ReactTransitionGroup = React.addons.TransitionGroup;
var EventTest = React.createClass({
render: function(){
return (
<ReactTransitionGroup component="ul" className="animated-list">
<li>test</li>
</ReactTransitionGroup>
);
}
});
React.render(<EventTest />, document.getElementById('container'));
</script>
</body>
</html>
実行していますが、動きません。エラーも吐きません。
生成されたhtmlを見てみます。
<div id="container">
<ul data-reactid=".0" class="animated-list">
<li data-reactid=".0.$=10">test</li>
</ul>
</div>
ちゃんと、ReactTransitionGroupが処理されているように見えますが、目的はアニメーションなので動かないと意味がありません。
これ、予想ですがanimated-listを何処かに定義する必要があるようにみえますが、情報が少なくてよく分かりませんね。
仕方がないので、高レベルの方を先にやってみましょう。
ReactCSSTransitionGroupを使う
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.slice();
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" transitionEnterTimeout={500} transitionLeaveTimeout={300}>
{items}
</ReactCSSTransitionGroup>
</div>
);
}
});
React.render(<TodoList />, document.getElementById('container'));
で、確認をすると。
ちゃんと行の追加と削除が出来るようになっていますね。
………、いやそうではなくて、今回の目的はアニメーションなんでと思っていたら、スタイルの指定がありました。
.example-enter {
opacity: 0.01;
}
.example-enter.example-enter-active {
opacity: 1;
transition: opacity 500ms ease-in;
}
.example-leave {
opacity: 1;
}
.example-leave.example-leave-active {
opacity: 0.01;
transition: opacity 300ms ease-in;
}
それを足すと、ようやくアニメーションしました!
う~ん、ReactではアニメーションはCSSで行う作りなんですね。
確かに、DOMを操作したJSよりも、CSSで行うほうが動作は早いらしいと聞きます。
もし、アニメーションを全てCSSで行えるようになるのであれば、その辺全てデザイナーにやって頂くことが出来そうですね、とても望ましい展開です。
まとめ
さて、本来であればここからより実践的なアプリを作る、、、といきたいところなんですが。
Reactだからこそ、といったものが全く浮かびません。
マスターとなるデータをDOMでは保持しないというのは、非常に共感出来る考え方でした。
DOMの全交換は遅いので、差分だけ更新というコンセプトも納得のいくものでした。
が、何故か手に馴染みません。
このコンポーネントを前提とした、構造が原因なのでしょうか?
このままでは次の記事を書くことが出来ないので、もう少し調べてみて、理解が深まったらその3を書こうかと思います。
それまでは記事としては保留ですね。
(もしかすると、チュートリアルを一からやってみる方がよかったかもしれません)
あと、まだまだ情報が少ないように感じました。
過去の資産を使うことも出来なくなるでしょうし、仕事で使うとを考えると、先の技術なのかな~とも思いました。
コメントを残す