React で前回と同一の React Node は re-render されない仮説

Published: 2023/10/14


例えば React.memo の公式資料 にて、以下の記述がある。

In practice, you can make a lot of memoization unnecessary by following a few principles:

  1. When a component visually wraps other components, let it accept JSX as children. This way, when the wrapper component updates its own state, React knows that its children don’t need to re-render.

どういうことかというと、 children を(直)描写する系の、ラッパー的なコンポーネントを記述したとき、ラッパー側の state が変更されただけならば、 children は re-render されない、ということ。

具体的にその振舞いについて検証を行ったコードの例などは、上記の記事などから参照できる。

仮説: reconciliation では、 Object.is 的に等価であれば、その先を re-render しない

上記の re-render 抑制の機構があるとして、シンプルで分かりやすい仮説は、 reconciliation の際に前回と今回の React Node を、 React がフレームワーク的に採用している等価性判定ロジックである、 Object.is でもって比較し、もしそれが真であるならば、その先の re-render を行わない、という振舞いをしていること、になる。

ラッパーコンポーネントと内部コンポーネントの JSX を記述した、それらの親コンポーネントの render の時点で、ラッパーに対する children 式は確定し、ラッパーが状態変化等により re-render する際であっても、親の re-render さえ起きていなければ、そこに渡る children の prop は不変であることが期待できる。

普通の React Component の記述において、親が re-render すると子も re-render していくのは、親が render した際に生成される React Node はオブジェクトなので、基本的に前回の render の結果とは、 Object.is 的には等価でないため、そのまま子コンポーネントの re-render が走っていく、のだと解釈できる。

そのような機構が動いている中で、きちんと React Element の type と 各 props の中身を等価性比較して、変わっていなければ re-render を抑制する機構として、 React.memo は用意されているのだ、と理解される。


Tags: react

関連記事