| ๋จ๊ณ | Render Phase (renderFiberNode) |
Commit Phase (commitFiberNode) |
๊ฒฐ๊ณผ |
|---|---|---|---|
| DOM ์ค๋น | Fiber ํธ๋ฆฌ๋ฅผ ์ํํ๋ฉฐ Text/Host DOM ์์ฑ๋ง ์ํ (๋ถ๋ชจ์ ์ฝ์ ํ์ง ์์) | effectTag(PLACEMENT/UPDATE/DELETION)์ ๋ฐ๋ผ ์ค์ DOM ์ฝ์ /์ฌ๋ฐฐ์น/์ ๊ฑฐ | React completeWork + commitMutationEffects์ ๋์ผ |
| ์์ ๊ฒฐ์ | Fiber child/sibling ๋งํฌ๋ง ๊ตฌ์ฑ | getHostSibling์ผ๋ก ๋ค์ ํ์ DOM ์ฐพ์ ๋ค insertBefore |
DOM ์์ ์์ |
| ์์ฑ/์คํ์ผ | ์ค์ ํ์ง ์์ | dom.updateAttributes / dom.updateStyles๊ฐ diff๋ฅผ ๊ณ์ฐํด Insert/Update/Delete ์ํ |
React commitUpdate์ ๋์ผ |
| ํ ์คํธ | Text node ์์ฑ๋ง | handleVNodeTextProperty๊ฐ ์ต์ข
ํ
์คํธ ์ปค๋ฐ |
Text-only VNode ์ฒ๋ฆฌ |
flowchart LR
A["VNode ์
๋ ฅ<br/>(prev / next)"]
B["Render Phase<br/>(renderFiberNode)"]
C["DOM ์์ฑ/์ฌ์ฌ์ฉ๋ง<br/>(์ฝ์
X, attrs X)"]
D["effectTag ๊ฒฐ์ <br/>(PLACEMENT / UPDATE / DELETION)"]
E["Commit Phase<br/>(commitFiberNode / commitFiberTree)"]
F["CL: effectTag === PLACEMENT?<br/>โ getHostSibling & insertBefore"]
G["์์ฑ/์คํ์ผ diff & ์ปค๋ฐ<br/>(dom.updateAttributes / updateStyles)"]
H["ํ
์คํธ ์ฒ๋ฆฌ<br/>(handleVNodeTextProperty)"]
I["์ต์ข
DOM ๋ฐ์ ์๋ฃ"]
A --> B --> C --> D --> E --> F --> G --> H --> I
flowchart LR
subgraph Prev_Render
P1["VNode_prev (sid/key)"] -->|metaDomElement| P2[DOM_prev]
end
subgraph Next_Render
N1[VNode_next] -->|transferVNodeIdFromPrev| N2["VNode_next + sid"]
N2 -->|generateVNodeIdIfNeeded fallback| N3["VNode_next stable ID"]
end
P2 -. reused DOM .-> N3
N3 -->|fiber.domElement| RenderPhase
RenderPhase -->|effectTag| CommitPhase
transferVNodeIdFromPrev: ์ด์ VNode์ sid/key๋ฅผ ์ VNode๋ก ๋ณต์ฌํด ๋์ผ ๊ฐ์ฒด์์ ํ์.generateVNodeIdIfNeeded: sid/key๊ฐ ์์ผ๋ฉด ์ปดํฌ๋ํธ(stype) โ ComponentManager, ์ผ๋ฐ Host โtag-index๊ธฐ๋ฐ auto ID ์์ฑ (DOM์๋ ๋ ธ์ถ๋์ง ์์).fiber.domElement๊ฐ prev DOM์ ๊ฐ๋ฆฌํค๊ฒ ๋์ด Commit Phase์์๋ ๊ฐ์ DOM์ ์ฌ์ฌ์ฉํ ์ ์์.
if (prevVNode?.meta?.domElement) {
domElement = prevVNode.meta.domElement;
} else if (vnode.tag === '#text') {
domElement = document.createTextNode(vnode.text);
} else if (vnode.tag) {
domElement = dom.createSimpleElement(vnode.tag);
if (vnode.sid && !isAutoGeneratedSid(vnode)) {
dom.setAttribute(domElement, 'data-bc-sid', vnode.sid);
}
if (vnode.attrs) {
for (const [key, value] of Object.entries(vnode.attrs)) {
dom.setAttribute(domElement, key, String(value));
}
}
}
vnode.meta.domElement = domElement;
fiber.domElement = domElement;- DOM ์์ฑ ํ
vnode.meta.domElement/fiber.domElement์ ์ ์ฅ. - ๋ถ๋ชจ์ ์ฝ์ ํ๊ฑฐ๋ ์์ฑ์ diffํ์ง ์์.
- Portal๋ ๋ณ๋ FiberScheduler๋ก ๋์ผ ํ๋ฆ ์ํ.
if (fiber.effectTag === 'PLACEMENT') {
const parent = fiber.parentFiber?.domElement ?? fiber.parent;
let before = getHostSibling(fiber);
if (before && before.parentNode !== parent) before = null;
parent.insertBefore(domElement, before);
}
if (domElement instanceof HTMLElement) {
dom.updateAttributes(domElement, prevVNode?.attrs, vnode.attrs);
dom.updateStyles(domElement, prevVNode?.style, vnode.style);
}
if (domElement instanceof HTMLElement && vnode.text && !vnode.children) {
handleVNodeTextProperty(domElement, vnode, prevVNode);
}- ์ฝ์
: Render Phase์์ ์ค๋น๋ DOM์ commit ์์ ์๋ง
insertBefore. - ์์ฑ/์คํ์ผ: React์ ๋์ผํ๊ฒ diff โ ๋ถ์กฑ๋ถ ์ญ์ , ์ ๊ฐ ์ ์ฉ.
- Deletion:
prevVNode.meta.domElement๊ธฐ๋ฐ์ผ๋ก DOM ์ ๊ฑฐ + component unmount.
let sibling = fiber.sibling;
while (sibling) {
if (sibling.domElement) return sibling.domElement;
if (sibling.child) {
let child = sibling.child;
while (child) {
if (child.domElement) return child.domElement;
child = child.child;
}
}
sibling = sibling.sibling;
}
return null;- Render Phase์์
domElement๋ฅผ ๋ฏธ๋ฆฌ ์ธํ ํ๊ธฐ ๋๋ฌธ์ commit์์ ๋ฐ๋ก reference node ํ๋ณด ๊ฐ๋ฅ. - reference node๊ฐ ๋ถ๋ชจ์ child๊ฐ ์๋๋ฉด
null๋ก ๊ฐ๋ฑ โ React์ ๋์ผํ append ๋์.
- Prev attrs์ ์์ง๋ง next attrs์ ์๋ ํค โ
removeAttributeWithNamespace๋ก ์ญ์ . - next ๊ฐ์ด
undefined/nullโ ์ญ์ ๋ก ๊ฐ์ฃผ. - ๋๋จธ์ง๋ namespace-aware
setAttributeWithNamespaceํธ์ถ.
- Prev ์คํ์ผ์ ์์ง๋ง next์ ์๋ ํค โ
style.removeProperty. - next ๊ฐ์ด
undefined/nullโremoveProperty. - ๋๋จธ์ง๋
style.setProperty๋ก ์ ๋ฐ์ดํธ.
- Text VNode๋ Render Phase์์
Text๋ ธ๋๋ง ์์ฑ. - Commit Phase์์
handleTextOnlyVNode/handleVNodeTextProperty๊ฐ ์ต์ข ํ ์คํธ ์ปค๋ฐ ๋ฐ ์์น ์ด๋์ ๋ด๋น.
effectTag === 'DELETION'โprevVNode.meta.domElement๋ฅผ parent์์ ์ ๊ฑฐ.- Component VNode์ด๋ฉด
components.unmountComponentํธ์ถ ํ DOM ์ ๊ฑฐ.
| React ๊ฐ๋ | ํ์ฌ ๊ตฌํ |
|---|---|
Fiber Render (beginWork/completeWork) |
renderFiberNode (DOM ์์ฑ๋ง) |
| Effect flags | fiber.effectTag (PLACEMENT/UPDATE/DELETION) |
| Effect list traversal | commitFiberTree (childโsibling DFS) |
commitPlacement |
insertBefore + getHostSibling |
commitUpdate (attrs/styles) |
dom.updateAttributes / dom.updateStyles |
getHostSibling |
๋์ผ ์๊ณ ๋ฆฌ์ฆ |
| namespace-aware attributes | setAttributeWithNamespace / removeAttributeWithNamespace |
๊ฒฐ๋ก : Render Phase์์ DOM์ ์ค๋นํ๊ณ , Commit Phase์์ ์ฝ์ /์์ฑ/์คํ์ผ/ํ ์คํธ/์ญ์ ๋ฅผ ์ํํ๋ React ํ๋ฆ์ ๊ทธ๋๋ก ์ฌํํ์ต๋๋ค.
Fiber ์์ฑ ์ prev/next VNode ์์ ๋งค์นญ์ ์๋ ์ฐ์ ์์๋ก ์งํ๋๋ค. ๊ฐ ๋จ๊ณ์์ ๋งค์นญ๋๋ฉด DOM์ ์ฌ์ฌ์ฉํ๊ณ effectTag = 'UPDATE', ๋๊น์ง ๋งค์นญ๋์ง ์์ผ๋ฉด ์ DOM์ ๋ง๋ค๊ณ effectTag = 'PLACEMENT'๊ฐ ๋๋ค. ๋งค์นญ์ ์คํจํ prev VNode๋ Commit Phase์์ removeStaleChildren์ด ์ ๊ฑฐํ๋ค.
| ์ฐ์ ์์ | ์กฐ๊ฑด | ๋งค์นญ ๊ธฐ์ค | ๊ฒฐ๊ณผ |
|---|---|---|---|
| 1 | getVNodeId(childVNode)๊ฐ truthy (sid, key, data-decorator-sid ๋ฑ) |
prevVNode.children ์ค ๋์ผ ID, ์์ง ๋งค์นญ๋์ง ์์ ํญ๋ชฉ ๊ฒ์ |
DOM/์ปดํฌ๋ํธ ์์ ์ฌ์ฌ์ฉ. ์์น๊ฐ ๋ฌ๋ผ๋ ํ์ฌ ์ธ๋ฑ์ค๋ก ์ด๋. |
| 2 | ๋ช
์ ID ์์, transferVNodeIdFromPrev๊ฐ stype ๊ธฐ๋ฐ ID๋ฅผ ๋ถ์ฌ |
prev ์์์ stype์ด ๊ฐ๊ณ ID๊ฐ ์๋ ๊ฒฝ์ฐ ID๋ฅผ ๋ณต์ฌ โ 1๋จ๊ณ์ ๋์ผํ๊ฒ ๋์ |
์ปดํฌ๋ํธ/Decorator๊ฐ ๋ช ์ ID ์์ด๋ ์์ ์ ์ผ๋ก ์ฌ์ฌ์ฉ๋จ. |
| 3 | ID ์์, ๊ฐ์ ์ธ๋ฑ์ค์ prev ์์ ์กด์ฌ | prev.children[i]์ tag์ ํ์ฌ tag๊ฐ ๊ฐ๊ฑฐ๋ ๋ ๋ค ํ
์คํธ (#text) |
๋์ผ ํ์ ์ผ ๋๋ง DOM ์ฌ์ฌ์ฉ. ํ์ ์ด ๋ค๋ฅด๋ฉด ๋งค์นญ ์คํจ. |
| 4 | ID/์ธ๋ฑ์ค ๋งค์นญ ์คํจ, ๋ ๋ค Host VNode | prev children ์ ์ฒด๋ฅผ ์ํํ๋ฉฐ tag + ํด๋์ค ์กฐํฉ์ด ๊ฐ์ ํญ๋ชฉ ํ์ (์ด๋ฏธ ๋งค์นญ๋ VNode ์ ์ธ) |
mark/decorator wrapper์ฒ๋ผ ID๊ฐ ์๋ Host ๋ ธ๋๋ ์์ ์ ์ผ๋ก ์ฌ์ฌ์ฉ. |
| 5 | ์ด๋ ์กฐ๊ฑด์๋ ํด๋นํ์ง ์์ | ๋งค์นญ ์คํจ๋ก ๊ฐ์ฃผ | Render Phase์์ ์ DOM ์์ฑ, Commit Phase์์ ๊ธฐ์กด DOM ์ ๊ฑฐ ํ ์ฝ์ . |
์ถ๊ฐ ๊ท์น:
- ํ
์คํธ ์์์
tag: '#text'๋ก ํต์ผํด 3๋จ๊ณ์์ ํ์ ๊ฒ์ฌ๊ฐ ์ผ๊ด์ ์ผ๋ก ๋์ํ๋ค. generateVNodeIdIfNeeded๊ฐ Host/Text VNode์tag-index๊ธฐ๋ฐ auto ID๋ฅผ ๋ถ์ฌํด ๋์ผ ๊ตฌ์กฐ๊ฐ ๋ฐ๋ณต๋ ๋๋ ๋งค์นญ์ด ์์ ์ ์ด๋ค.- Render Phase๋ ๋งค์นญ ๊ฒฐ๊ณผ๋ง ๊ณ์ฐํ๊ณ DOM ์ด๋/์ญ์ ๋ ํ์ง ์๋๋ค. Commit Phase์์
commitFiberTree๊ฐ effectTag์ ๋ฐ๋ผ DOM์ ์ฝ์ ยท์ ๋ฐ์ดํธยท์ญ์ ํ๊ณ , ๋ง์ง๋ง์removeStaleChildren/processPrimitiveTextChildren๊ฐ ๋จ์ ๋๊ธฐํ๋ฅผ ์ํํ๋ค.
flowchart TD
A[Next child VNode] --> B{getVNodeId ์กด์ฌ}
B -->|Yes| C[prev.children ์ค ๋์ผ ID & ๋ฏธ๋งค์นญ ํญ๋ชฉ]
C --> D[DOM ์ฌ์ฌ์ฉ<br/>effectTag = UPDATE]
B -->|No| E{transferVNodeIdFromPrev ๊ฒฐ๊ณผ ID}
E -->|Yes| C
E -->|No| F{๊ฐ์ ์ธ๋ฑ์ค prev child}
F -->|Yes, tag ๋์ผ| D
F -->|No| G{Host ๊ตฌ์กฐ ๋งค์นญ}
G -->|Yes| H[prev ์ ์ฒด ์ํ<br/>tagยทclass ๋์ผ ๋
ธ๋]
H --> D
G -->|No| I[์ Fiber/DOM ์์ฑ<br/>effectTag = PLACEMENT]
D --> J[Commit Phase์์ ๊ธฐ์กด DOM ์์น๋ณด์ ]
I --> K[Commit Phase์์ ์ DOM ์ฝ์
]
J --> L[removeStaleChildren๋ก ์ฌ์ฉ๋์ง ์์ prev DOM ์ ๊ฑฐ]
K --> L
์ ๋ค์ด์ด๊ทธ๋จ์ Render Phase์ Commit Phase ๊ฐ์ ์ญํ ๋ถ๋ฆฌ๋ฅผ ์๊ฐํํ๋ค. Render Phase๋ ๋งค์นญ ๊ฒฝ๋ก๋ฅผ ๊ฒฐ์ ํ๊ณ fiber.effectTag๋ง ์ค์ ํ๋ฉฐ, Commit Phase๋ effectTag์ ๋ฐ๋ผ DOM์ ์ฝ์
ํ๊ฑฐ๋ ์ฌ๋ฐฐ์นํ ๋ค ๋จ์ prev DOM์ ์์ ํ๊ฒ ์ ๊ฑฐํ๋ค.
Render Phase์์๋ ์ค์ง diff ๊ณ์ฐ๊ณผ effectTag ์ง์ ๋ง ์ํํ๊ณ ์ด๋ค DOM ์กฐ์๋ ํ์ง ์๋๋ค. Mount, Update, Unmount๋ ๋ชจ๋ Commit Phase์์ effectTag๋ณ๋ก ์ฒ๋ฆฌ๋๋ค.
| effectTag | ์์ | ์คํ ํจ์ | ์ํ ์์ |
|---|---|---|---|
PLACEMENT |
Commit Phase์ commitFiberNode โ commitPlacement ๊ตฌ๊ฐ |
insertBefore + getHostSibling |
์ DOM ์ฝ์ , decorator/portal ํฌํจ |
UPDATE |
Commit Phase์ commitFiberNode ๋ณธ๋ฌธ |
dom.updateAttributes, dom.updateStyles, ํ
์คํธ ๊ฐฑ์ , ์์ Fiber parent ๊ฐฑ์ |
๊ธฐ์กด DOM ์ ์งํ ์ฑ ์์ฑยท์คํ์ผยทํ ์คํธ diff ๋ฐ์ |
DELETION |
Commit Phase์ commitFiberNode (vnode ์์) + ๋ถ๋ชจ removeStaleChildren |
components.unmountComponent, removeChild |
prev DOM ์ ๊ฑฐ ๋ฐ ์ปดํฌ๋ํธ ์ธ๋ง์ดํธ, primitive text ํฌํจ |
sequenceDiagram
participant Scheduler as FiberScheduler
participant Render as Render Phase<br/>(renderFiberNode)
participant Commit as Commit Phase<br/>(commitFiberTree)
participant DOM as ์ค์ DOM
participant Components as ComponentManager
Note over Scheduler: reconcileWithFiber ์์
Scheduler->>Scheduler: scheduleWork(rootFiber)
Scheduler->>Render: performUnitOfWork<br/>(Fiber DFS ์ํ)
loop Render Phase (๊ฐ Fiber ๋
ธ๋)
Render->>Render: transferVNodeIdFromPrev
Render->>Render: generateVNodeIdIfNeeded
Render->>Render: ํ์
๋น๊ต (prevType vs nextType)
Render->>Render: effectTag ๊ฒฐ์ <br/>(PLACEMENT/UPDATE)
alt prevVNode.meta.domElement ์กด์ฌ & ํ์
๋์ผ
Render->>Render: ๊ธฐ์กด DOM ์ฌ์ฌ์ฉ
else ์ DOM ์์ฑ ํ์
Render->>Render: createTextNode ๋๋<br/>createSimpleElement
Render->>Render: attrs ์ค์ (DOM์ ์ ์ฅ)
end
Render->>Render: vnode.meta.domElement ์ ์ฅ
Render->>Render: fiber.domElement ์ ์ฅ
Note over Render: DOM ์กฐ์ ์์<br/>(์์ฑ๋ง)
end
Scheduler->>Scheduler: Render Phase ์๋ฃ
Scheduler->>Commit: onCompleteCallback<br/>(commitFiberTree ํธ์ถ)
loop Commit Phase (๊ฐ Fiber ๋
ธ๋)
Commit->>Commit: commitFiberNode (DFS ์ํ)
alt effectTag = PLACEMENT
Commit->>Commit: getHostSibling (referenceNode ์ฐพ๊ธฐ)
Commit->>DOM: insertBefore (DOM ์ฝ์
)
Note over Commit,DOM: mount (DOM์ ์ถ๊ฐ)
else effectTag = UPDATE
Commit->>DOM: updateAttributes (diff ์ ์ฉ)
Commit->>DOM: updateStyles (diff ์ ์ฉ)
alt Text ๋
ธ๋
Commit->>DOM: textContent ์
๋ฐ์ดํธ
end
Note over Commit,DOM: update (์์ฑ/์คํ์ผ/ํ
์คํธ ๊ฐฑ์ )
else effectTag = DELETION
Commit->>Components: unmountComponent
Commit->>DOM: removeChild
Note over Commit,DOM: unmount (DOM ์ ๊ฑฐ)
end
end
Commit->>Commit: processPrimitiveTextChildren<br/>(primitive text ์ฒ๋ฆฌ)
Commit->>DOM: removeStaleChildren<br/>(์ฌ์ฉ๋์ง ์์ DOM ์ ๊ฑฐ)
Commit->>Components: unmountComponent<br/>(stale ์ปดํฌ๋ํธ ์ธ๋ง์ดํธ)
์ ์ํ์ค๋ FiberScheduler๊ฐ Render Phase๋ฅผ ์ค์ผ์ค๋งํ๊ณ , Render Phase๊ฐ effectTag๋ง ๊ณ์ฐํ๋ฉฐ, Commit Phase๊ฐ mount/update/unmount๋ฅผ ์ค์ DOM์ ์ ์ฉํ๋ ์ ์ฒด ํ๋ฆ์ ๋ณด์ฌ์ค๋ค.
์ฃผ์ ํฌ์ธํธ:
- FiberScheduler:
reconcileWithFiber์์ ์์ฑ๋์ด Render Phase๋ฅผ ๋น๋๊ธฐ๋ก ์ค์ผ์ค๋ง (ํ ์คํธ ํ๊ฒฝ์์๋ ๋๊ธฐ ๋ชจ๋) - Render Phase: DOM ์์ฑ๋ง ์ํํ๊ณ ์ฝ์
/์์ ์ ํ์ง ์์.
mountComponent/updateComponent๋ ํธ์ถํ์ง ์์ (ํฅํ ์ถ๊ฐ ์์ ) - Commit Phase: effectTag์ ๋ฐ๋ผ ์ค์ DOM ์กฐ์ ์ํ.
unmountComponent๋ง ํธ์ถ (์ญ์ ์)
ํ์ฌ Fiber reconciler์์๋ mountComponent/updateComponent๋ฅผ ํธ์ถํ์ง ์์ง๋ง, ๊ธฐ์กด reconciler์ ๋์์ ์ฐธ๊ณ ํ๋ฉด ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํ๋ ์์ ์ด๋ค:
mountComponent ํธ์ถ ์์ :
createHostElement์์ ์ Host element ์์ฑ ํ (๊ธฐ์กด reconciler)- Fiber reconciler์์๋
commitFiberNode์PLACEMENT๊ตฌ๊ฐ์์ ํธ์ถ ์์
updateComponent ํธ์ถ ์์ :
updateHostElement์์ ๊ธฐ์กด Host element ์ ๋ฐ์ดํธ ์ (๊ธฐ์กด reconciler)- Fiber reconciler์์๋
commitFiberNode์UPDATE๊ตฌ๊ฐ์์ ํธ์ถ ์์ - ํธ์ถ ์ ์ ๋ฌ๋๋ ๋ณ๊ฒฝ ์ฌํญ:
components.updateComponent(prevVNode, nextVNode, host, context); // ๋ด๋ถ์์ ๋ค์ ํญ๋ชฉ๋ค์ด ์ ๋ฐ์ดํธ๋จ: // - instance.props = nextSanitizedProps (prevVNode.props์ diff) // - instance.model = nextModelData (prevVNode.model๊ณผ diff) // - instance.decorators = nextDecorators (prevVNode.decorators์ diff) // - instance.vnode = nextVNode // - component.update(host, prevVNode.props, nextVNode.props) (props ๋ณ๊ฒฝ ์)
unmountComponent ํธ์ถ ์์ :
commitFiberNode์์effectTag === 'DELETION'์ผ ๋removeStaleChildren์์ ์ฌ์ฉ๋์ง ์์ ์ปดํฌ๋ํธ ์ ๊ฑฐ ์