ReactでTable要素のmount(描画)に時間がかかる問題を初回の描画を切り捨てることで解決しました

事案

React + ReduxでTableの描画に10秒程度かかる.

要素は多くて700件ぐらい.

やりたいこと

描画を2秒ぐらいにはしたい.

やってたこと

  • Reduxのデータ構造見直し
  • Reduxのデータをなるべく更新しないようにする
  • mainプロセスの処理最適化
  • 階層を小さく

全て無駄だった

そもそもupdateではなくmountに時間がかかっているのですからやってたことは全て無駄.

更新減らすとかも無駄.

ページャ作れば良い

Table要素はどうせ大半はファーストビューに含まれないのですから範囲外の要素は描画しなければ良い.

つまりページャを実装すれば良い.

一般的に範囲外要素を描画しないミドルウェア的なものがあった気がするんですがググっても出てこない.

react-virtualizedでした.

まあ今回は700件程度なのでこれ使うのはオーバーキルっぽいですね.

追加で操作は要求できない

ユーザ操作を必要とするものは受け入れられない.ひっそりとシームレスに動かす必要がある.

スクロールをイベントにする?

スクロールが最後まで来たことを感知して全て表示するように切り替えれば良いのでは?

スクロールイベント取ってスクロールの座標計算するの面倒くさい.座標計算苦手なので絶対バグが発生する

componentDidMountとsetTimeoutで良くない?

ファーストビューを早くしたいだけなんですから確かにそうですね.componentDidMountの中でwindow.setTimeout呼んで,this.setStateしてsliceの制限をundefinedにすることで解決です.

ページャではないけど,初回読み込みの切り捨てで解決です.

得られたパフォーマンス

ファーストビューは1秒程度にはなりました.

本当はスクロールを取得した方が良いと思います

時間が来ると画面が一瞬ですが固まってしまいますね.

スクロールというユーザの入力に反応して次を読み込む方が直感的でユーザ体験が良さそうです.まあ今回はそこまで作り込む必要なさそうなのでsetTimeoutで済ましてしまいますが.

Reactにジェネレータを渡せれば良いのに

普通の配列じゃなくてジェネレータを渡して,Reactがそれを呼び出してくれれば,DOM構築が終わった順にmountされて,setTimeoutなんて不格好なことをしなくても順に描画されたのですが.

提案はあったようですが,残念ながら却下されていますね.Allow generators (that yield components) in place of arrays · Issue #7536 · facebook/react

まあ仕方がないですね.

全て無駄というほどではなかった

切り捨てを導入してmount処理が大部分のコストじゃなくなった後に,パフォーマンスモニタを見てわかりましたが.最適化は全て無駄というほどでは無かったようですね.

本当はネットワーク通信がページャに対応してるのが一番良いんです

結局ネットワーク全部読んでsortする必要があります.リクエストでソート条件とページングを指定できるサーバAPIがあるのが理想.フロントエンド側ではやれることが少ないですね.

このエントリーをはてなブックマークに追加 fb-like g-plusone pocket