Tips 1:React.jsならではのパフォーマンスチューニング
React.jsでは、パフォーマンスチューニングのために簡単なアドオン「React.addons.Perf」が用意されています。React.addons.Perfを用いることによって、ボトルネックになっているコンポーネントを詳細に知ることができます(公式ドキュメントも参照)。
| メソッド | 定義と用途 |
|---|---|
| Perf.start()、Perf.stop() | 計測を開始、終了する |
| Perf.printInclusive(measurements) | コンポーネント内で費やされた処理時間を表示する |
| Perf.printExclusive(measurements) | コンポーネント内で費やされた処理時間(ただしマウント時を除く)を表示する |
| Perf.printWasted(measurements) | 実際にはDOMに何も影響を及ぼさなかったにもかかわらず消費された時間を表示する |
| Perf.printDOM(measurements) | DOMの処理(例えば"set innerHTML"や"remove")に費やした時間を表示する |
| Perf.getLastMeasurements() | 最後の計測結果の詳細をオブジェクトとして返す |
表の中で特に便利なメソッドがPerf.printWasted()で、実際にはDOMに何も影響を及ぼさなかったにもかかわらず消費された時間を表示します。言い換えれば、前回からの差分がないVirtual DOMを余計に生成した時間にあたります。
コストの低いVirtual DOMの生成とはいえ、無駄だと分かっている処理ならしないに越したことはありません。この時間を削るためには、コンポーネントの描画が必要ない場合にはfalseを返すように、コンポーネントのshouldComponentUpdate()メソッドを上書きしてやります。これにより、確実にパフォーマンスを上げることができます。
例えば、画面の初期化時や新しいTODOを追加したときの描画処理は、<App>コンポーネント中で次のように計測できます。
var React = require('react/addons');
+var Perf = React.addons.Perf;
...
var setTodoState = function() {
TodoStorage.getAll(function(todos) {
+ Perf.start();
this.setState({
todos: todos
+ }, function() {
+ Perf.stop();
+ Perf.printWasted();
});
}.bind(this));
}.bind(this);
TodoStorage.on('change', setTodoState);
setTodoState();
| (index) | Owner > component | Wasted time (ms) | Instances |
|---|---|---|---|
| 1 | "TodoList > TodoForm" | 2.171000000089407 | 2 |
ここでは、Perf.printWasted()メソッドによって、若干ですが<TodoForm>コンポーネントが無駄な処理を行っていることが分かりました(サンプルが小規模のため2ミリ秒で済んでいますが)。
そこで、<TodoForm>コンポーネントのshouldComponentUpdate()メソッドを上書きします。
shouldComponentUpdate: function(nextProps, nextState) {
return this.state.name !== nextState.name;
},
これでテーブルに何も表示されなくなりました。もちろん動きに不備がないかも確認しましょう。
shouldComponentUpdate()メソッドは便利ですが、普段から神経質になって使う必要はありません。パフォーマンスチューニングは「正しく計測した結果、ボトルネックだと分かった場所から順につぶす」という基本に忠実に行いましょう。
