reactjs

reactのshouldComponentUpdateについて

More than 1 year has passed since last update.

気持ち

ReactのComponentは、stateが更新されるとコンポーネントが丸っと再描画されます。このとき、Virtual DOMのおかげで差分のみがDOMに反映されるので、性能をそんなに劣化させる事なくUI制御をすることが可能になります。

でも、アプリで表示するデータがFBのタイムラインみたいに無限に取得できるような画面の場合、いくらVirtual DOMといえどもさすがに辛いのでは。さらに、もしそのデータがネストしていたら、実際に描画しないとしてもネスト部分のループ処理は行われるわけだよね?実際どうなの?

調べてみた

ということで、jsperfで実際にやってみました。

[
  {
    id: 1,
    firstName: 'xxx',
    lastName: 'XXX',
    children: [...]
  },
  ...
]

という感じのネストしたデータを大量に表示するコンポーネントを二つ用意し、一つは何も考えずにコンポーネントを定義、もう一つはshouldComponentUpdateを使って、childrenの配列に変化がなければ(つまり !== で比較してfalseであれば)childデータの表示コンポーネントは再描画しない、というようにしています。

shouldComponentUpdateは、コンポーネントを再描画するかどうかを決定するAPIで、defaultは常にtrueを返す、つまり常に再描画するようになっています。
https://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate

結果はこちら
http://jsperf.com/react-performance-shouldcomponentupdate
(表示が重いのでブラウザ一瞬固まるかも。固まってもそっとしといて)

root2のほうがshouldComponentUpdateを使った結果ですが、結果は明白ですね。

1秒間に10回再描画処理(実際には何もしてない)が走るのに対し、shouldComponentUpdateを使わない方は1秒間に1回の描画すらできていません。

とはいえ

shouldComponentUpdateを使うと、コンポーネントのメンテナンスコストも上がりますし、この差分チェックロジックにバグがあれば意図した通りにUIが反映されない、という辛いバグにぶつかるかもしれません。今回の例だと、dataコンポーネントの表示全体としては問題ないけど、なぜかchildlenデータ部分の表示だけおかしい、みたいなことが起きるかもしれません。FBが推奨するようにimmutable-jsとPureRenderMixinを組み合わることを考えた方が良いかも。

まとめ

性能面が問題になるくらいに複雑なデータを表示しないのであればこのAPIを使う必要はなさそうですが、万が一性能が問題になった時はshouldComponentUpdateで回避できることを思い出そう。