Help us understand the problem. What is going on with this article?

ReactでshouldComponentUpdateを使ったチューニングの効果と注意どころ

More than 3 years have passed since last update.

GitHubはこちら

背景

Reactが流行ってる理由として、
Fluxやもともとのフレームワークの用法からデータフローが単方向へと簡略化され、速度面ではチューニングしたDOMを直接触る従来の方式には敵わないが、遅くなる事はないし何よりシンプルな方向へとバイアスがかかる恩恵がでかい、というのが自分の中での認識となっています。

ただ、速度は速い方が嬉しいので、フレームワークのベンチマーク比較プロジェクトに、shouldComponentUpdateを実装して、必要時にだけrenderが呼ばれるようにチューニングをしてどれだけ効果があるのかを検証してみた、というのが今回の記事です。

プロジェクトはこちらの記事のをForkして利用しています。

計測結果

benchmark.png

上から、

  • Backboneの部分的再描画、
  • Backboneの全再描画
  • ReactのVirtualDOM全再描画、
  • ReactのVirtualDOM部分再描画(shouldComponentUpdateの手動チューニング)、
  • ReactのVirtualDOM部分再描画(shouldComponentUpdateチューニングに自作の汎用Mixinの利用)

となっています、shouldComponentUpdateの実装はかなり効果があるものと言えます。

shouldComponentUpdateで比較時の注意どころ

test.js
  shouldComponentUpdate: function(nextProps, nextState) {
    if (差分があった) {
      return true;
    }
    else {
      return false;
    }
  }

基本的に、やる事と言えばメンバのthis.props、this.stateと、引数のnextProps、nextStateとで差異があればtrueを返すだけで良いのですが、愚直にメンバの比較を羅列するのはこのメソッドのメンテナンスコストがかなり高くなってしまいます(効果は高いですが)。

また、シャローコピーされた参照型がプロパティに含まれている場合は、比較しても常にtrueが返ってしまい、誤動作の原因となってしまいます。

ng.js
  this.state.shallowedInstance === nextState.shallowedInstance; // FIXME : 常にtrue

全てのプロパティが値型なのであれば、PureRenderMixinアドオンが提供されているため、それを使うことが出来ますが、参照型の場合は別の手を考える必要があります。

メンテナンスコストを緩和する今回の対策

今回の対応方法としては、公式でも使用を推奨しているimmutable-jsを使い、Mixinとして使えるようにして、shouldComponentUpdateを使った時のメンテナンスコストを下げれるように図ってみました、速度は計測結果の一番下です、場合にもよりますが、効果はある方なんじゃないかと思います。

mixin.js
var Immutable = require('immutable');
var Mixin = {
  prevPropsMap: undefined,
  prevStateMap: undefined,

  getInitialState: function() {
    this.prevPropsMap = Immutable.Map();
    this.prevStateMap = Immutable.Map();

    return {};
  },

  shouldComponentUpdate: function(nextProps, nextState) {
    var nextPropsMap = Immutable.Map(nextProps);
    var nextStateMap = Immutable.Map(nextState);

    if (!Immutable.is(nextPropsMap, this.prevPropsMap) ||
        !Immutable.is(nextStateMap, this.prevStateMap)) {

      this.prevPropsMap = nextPropsMap;
      this.prevStateMap = nextStateMap;
      return true;
    }

    return false;
  }
};

使い方は、mixinsにこちらのmixinオブジェクトを指定して使います。
ちなみにGitHubのプロジェクトにもソースあります
(todomvc/react3/js/components/ShouldComponentUpdateMixin.react.js)。

参考

https://facebook.github.io/react/docs/advanced-performance.html

wordijp
C++が好きです(C++の記事を投稿するとは言っていない)
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした