再描画はなぜ起きるか — 1 文字打つたびに、表ぜんぶが描き直されていた
検索欄に 1 文字打つたびに、画面が 0.4 秒固まった。メモ化を全部の部品に付けても変わらなかった。描き直される範囲は、状態を持つ場所で決まる。
この記事の進み方
What — 何が、どこまで描き直されるか
React のような UI の仕組みでは、画面を部品(コンポーネント)の木として組みます。各部品は「状態を受け取って、画面の形を返す関数」です。
状態が変わると、次のことが起きます。
- その状態を持つ部品が、関数をもう一度実行する(これを再描画と呼ぶ)
- その部品が返す子の部品も、すべてもう一度実行される
- 前回の結果と比べ、違いがあった部分だけを実際の画面(DOM)に反映する
大事なのは、2 と 3 が別だという点です。画面に反映されるのは違いの分だけでも、関数の実行は子孫ぜんぶに及びます。5,000 行の表なら、5,000 回の関数の実行と比較が走ります。
検索の文字を、画面の親に持たせる。
画面(検索の文字を持つ) ├ 検索欄 ├ 並べ替えボタン └ 表 └ 行 × 5,000 1 文字 → 画面から下を全部実行
- 1 文字で実行する部品
- 約 5,000
- 入力の遅れ
- 0.4 秒
- 書きやすさ
- 書きやすい
- 1 回で実行する行
- —
- 作る手間
- —
- –状態を上に集めると、どこからでも使えて書きやすい。その代わり、変わるたびに下ぜんぶが動く。
- –冒頭の事故はこれ。
同じ画面、同じ状態。置く場所だけが違う。
メモ化が効く条件
「子の部品は、渡された値が前回と同じなら、実行を飛ばす」。これがメモ化です。ただし「同じ」は、中身ではなく参照で比べます。
// 描画のたびに新しいオブジェクトと関数を作って渡している
<Row style={{ color: "gray" }} onClick={() => select(id)} />
// 中身が同じでも、毎回「別のもの」なので、メモ化は効かない
メモ化が効くのは、渡す値が本当に前回と同じもののときだけです。オブジェクトや関数を渡すなら、それ自体も同じものを使い回す必要があります。冒頭の担当者は、行をメモ化した一方で、渡す値を毎回作り直していました。
画面の親の部品が状態を 1 つ持っています。その状態が変わったとき、関数がもう一度実行されるのはどこまでですか?
Why — なぜ「全部メモ化」では直らないのか
状態を上に置くのは、書きやすいから
状態を画面のいちばん上に集めると、どの部品からも使えて、受け渡しに悩みません。書きやすさを得て、描き直す範囲の広さを払っています。部品が少ないうちは、この払うものは見えません。表が 5,000 行になったときに現れます。
メモ化は、範囲を狭める道具ではない
メモ化は、広い範囲が描き直される前提で、その中の一部を飛ばす道具です。状態が上にある限り、描き直しの呼びかけは表ぜんぶに届きます。メモ化はそれを 1 つずつ断っているだけで、しかも断るための比較にも費用がかかります。
範囲を狭めるのは、状態を使う場所の近くに置くことです。こちらは呼びかけ自体が届かなくなります。
測ってから直す
再描画は、見えないので推測で直しがちです。直す前に測ります。
- 開発者ツールのプロファイラで、1 回の操作でどの部品が、何ミリ秒かけて実行されたかを見る
- 利用者の側では、操作から画面の反応までの時間(Core Web Vitals の INP)で見る
このサイト自身も、図解の再描画を測ったうえで、メモ化を自動で入れる仕組みを入れないと決めています。1 回の操作が 0.2 ミリ秒で、削る余地が無かったためです。測らずに入れると、測れない差に費用を払います。
行の部品をメモ化したのに、親が再描画されるたびに全行が再実行されます。最も疑わしい原因はどれですか?
演習 — まず自分で判断する
解説を読む前に、まず自分で判断してみてください。ここで一度詰まっておくと、 次の節の判断軸が「なるほど」ではなく「そう来たか」に変わります。
冒頭の顧客管理画面の遅さを、どの順で直しますか?
- 検索欄の文字は、画面いちばん上の部品の状態にある
- 表は 5,000 行。1 行に 8 列。行とセルはすべてメモ化済みだが効いていない
- 並べ替えのボタンと、選択中の行の数を示すバッジも、同じ親の状態を使っている
- 来週までに、入力の遅れを体感できないところまで直したい
- · 描き直しの範囲を決めているのはどこか
- · 今のメモ化が効いていない理由は何か
- · 直す前に、何を測って効果を確かめるか
「再描画が遅いときは、とりあえず全部の部品をメモ化すればいい」と言う後輩に、それでは足りない理由を説明してください
- 相手はメモ化の書き方は知っているが、仕組みは理解していない
- 相手のチームには、メモ化だらけで遅いままの画面がある
- 何から見ればよいかまで示したい
読み終わりましたか?
読了にすると、これを前提とする記事がロードマップで開放されます。