Join the discussion
Comments
Loading comments...
Cookie preferences
We use essential cookies for sign-in and preferences. With your permission, we also use basic analytics to improve lessons.
Join the discussion
Loading comments...
We use essential cookies for sign-in and preferences. With your permission, we also use basic analytics to improve lessons.
Reactが仮想表現を作成し、最小限のDOM変更を見つけるためにdiffingする仕組み。
仮想DOMは、実際のDOMを模した軽量なJavaScriptオブジェクトツリーです。Reactは2つのコピーを保持します:現在のツリーと、各レンダリング中に構築される「work-in-progress」ツリーです。実際のDOMをすぐに操作する代わりに、Reactは2つの仮想ツリーを比較して必要な最小限の変更セットを計算し、それらを1つのバッチで適用します。
JSXを書くと、Babel(またはReactコンパイラ)がそれをReact.createElement(type, props, ...children)呼び出しに変換します。これらは実際のDOMノードではなく、Reactエレメントと呼ばれるプレーンなJavaScriptオブジェクトを返します。
React.createElement()は'{' type: 'div', props: '{' className: 'box', children: [...] '}' '}'のようなネストされたオブジェクトツリーを返します。これが仮想DOM — UIがどのように見えるべきかを表す安価なインメモリの記述です。
stateやpropsが変更されると、Reactはコンポーネント関数を再度呼び出し、新しい望ましいUIを表すまったく新しい仮想DOMツリーを生成します。
ReactのdiffingアルゴリズムはO(n)のヒューリスティックで、両方のツリーを同時に走査します。異なる型の要素は異なるツリーを生成すると仮定し、key propを使ってレンダリングをまたいでリストアイテムをマッチングします。
diffing後、Reactは変更のリストを持ちます:このpropを更新、このノードを挿入、あのノードを削除。これらはコミットフェーズで実際のDOMに適用され、リフローと再描画を最小化します。
React.createElement()が返すプレーンなJSオブジェクト。型、props、childrenを記述します。実際のDOMノードではありません。
2つの仮想ツリーを比較するReactのO(n)ヒューリスティック。keyが異なる場合を除き、同じ位置の要素は同じ型であると仮定します。
古い仮想ツリーと新しい仮想ツリーを比較し、必要な最小限のDOM操作セットを決定するプロセス。
リストアイテムの安定した識別子。位置が移動しても古いリスト要素と新しいリスト要素をマッチングできます。
ReactはリコンシリエーションパスからのすべてのDOM変更をまとめて適用し、ブラウザのリフローを削減します。
1// JSX you write:2const element = <div className="box"><span>Hello</span></div>;34// Compiles to:5const element = React.createElement(6 'div',7 { className: 'box' },8 React.createElement('span', null, 'Hello')9);1011// Produces this Virtual DOM object:12{13 type: 'div',14 props: {15 className: 'box',16 children: {17 type: 'span',18 props: { children: 'Hello' }19 }20 }21}
直接のDOM操作は、ブラウザがレイアウトを再計算して再描画する必要があるため、高コストです。JavaScriptでdiffing(高速)しDOMへの書き込みをバッチ処理(低速)することで、Reactは高コストなブラウザ操作の回数を最小化します。これがReactアプリが複雑なUIでも高速に感じられる理由です。
You have a chat app rendering 500+ messages. Scrolling to load older messages causes the entire message list to re-render, taking 300ms and causing visible lag.
When new messages are appended, React creates a new VDOM tree for the entire list. The diffing algorithm walks all 500+ nodes even though only 20 new messages were added.
Use windowing (react-window/react-virtualized) to only render visible messages in the VDOM. Combined with proper `key` props, React's diff only processes ~20 visible nodes instead of 500+. The VDOM tree stays small, diffs stay fast.
Takeaway: The VDOM's diffing cost is proportional to tree size, not DOM size. Keeping your VDOM tree small via virtualization is the most effective optimization for large lists.
A component receives `style={{ color: 'red' }}` as a prop. Despite no visual change, React DevTools shows it re-renders on every parent update.
Each render creates a NEW style object `{ color: 'red' }`. When React diffs oldProps vs newProps, `oldStyle !== newStyle` (different object reference), so React marks this node as 'changed' and commits a DOM update — even though the actual CSS hasn't changed.
Hoist the style object outside the component or wrap it in `useMemo`. Now `oldStyle === newStyle` (same reference), the diff correctly marks it as 'unchanged', and React skips the DOM write entirely.
Takeaway: Understanding how the VDOM diff compares props (by reference, not deep equality) reveals why inline objects, arrays, and arrow functions in JSX cause performance issues.