Code

2016年2月21日日曜日

React.js もっと速くするコツ

TL; DR:
    React.js Component を作る際:
 1 shouldComponentUpdate 関数は必ず入れましょう。または pureRenderMixin みたいなモジュールを使いましょう。
 2 Component は state を持つであれば、最小限の Component にしましょう。そうすると、setState は最小限 render() 関数を呼び出すし、最小限の DOM 更新します。
 3 App に state を置いて、各 Component はできるだけ props を使いましょう。もしいっぱい props があったら、Babel を使って、 {...obj} みたいなシンタックスを使いましょう。

本文:
 リリース日が近づいてきました。今作ってる Single Page Web App はもう一丁大きくなって、HTML Node の数は 20k 超えました。AngularJS の場合、もうなんかしないといけないサイズになりますが、React.js はサクサク動くだけです。この辺は DOM 操作とJavaScript 処理の差が出ました。
 ただ、React.js を使うだけで、Web App が速くなることではないと思います。やはり前書いたように AngularJS みたいに作り方次第です。AngularJS と同様、React.js Web App を速くする方法は必要なときだけ、データとDOMを更新して、また更新する必要な場所だけ更新します。
 AngularJS 1.0 の Dirty Check みたいに、React.js App を更新するには setState() という関数があります。this.setState({newState: newState}) を呼ぶと、その Component の render() 関数が呼ばれて、さらに、Component Tree の比較と行われます。そうすると、React.js は Virtual DOM の変化をキャッチして、実際の DOM を更新します。ただ、Component の render() 関数を呼ぶべきかどうかは shouldComponentUpdate() という関数がコントロールしています。デフォルトでは shouldComponentUpdate() は return true; のみです。この関数は必ず自分で書くべきです。または pureRenderMixin を使って、Component が更新必要なときだけ、true を返して、そうでない場合、false を返すべきです。
 さらに、Component は state を持つべきかどうかをよく考えないといけません。一般的に、Web App 全体の App Component に state を置いて、その他の Component は props のみ使うべきです。ただし、carousel や、toggle button みたいな自分の state が必要なとき、state を使いましょう。
 例えば、App の構造は:
    <div className="app">
        <panel1 data={this.state.data1} />
        <panel2 data={this.state.data2} />
    </div>

   App の state に data1, data2 が store から取得して、もし変化がある場合、this.setState({data1: newData}) を呼び出したら、panel1 は更新すべきですが、data2 が変わってないので、 panel2 はこの更新をスキップするために、panel2 component の shouldComponentUpdate 関数は
    return this.props.data2 !== nextProps.data2;
を書くべきです。もし data2 は複雑な object や、array の場合、deep check は難しいであれば、更新もそんなに頻繁ではない場合、いつも新しい object を作ってもいいようが気がします。
 そうでないと、React.js はいくら速くても、アプリの作りによる重くなることもありうるし、AngularJS より軽いですが、AngularJS みたい遅くなるケースもあります。