영문 블로그 글을 번역했습니다. 허가를 받으면 시리즈를 이어갈 예정입니다.
원문링크:https://jser.dev/react/2022/01/16/fiber-traversal-in-react
ℹ️React Internals Deep Dive에피소드 15,유튜브에서 제가 설명하는 것을 시청해주세요.
⚠React@18.2.0기준, 최신 버전에서는 구현이 변경되었을 수 있습니다.
💬 역자 주석: JSer의 코멘트는 ❗❗로 표시 해뒀습니다.
그 외 주석은 리액트 소스 코드 자체의 주석입니다.
... 은 생략된 코드입니다.
Fiber Tree 구조
앞서 설명했듯이, React는 내부적으로 파이버 트리를 유지하며 계속 업데이트합니다. 각 파이버 노드에는 구조를 형성하는 3가지 프로퍼티가 있습니다.
child
, 이름에 따라 그 자식 파이버.sibling
, 이름에 따라 그 형제 파이버return
, (일종의)부모 파이버라고 생각할 수 있습니다.
children
이 없기 때문에, 제가 추측하기로 React 팀은 트리 탐색을 가능한 한 간단하게 처리하고 싶기에, 이 세 가지 프로퍼티는 충분히 잘 작동할 것입니다.
이런 일이 있을 수 있습니다.
Fiber Tree는 어떻게 순회하는가
파이버 트리를 순회해야 하는 많은 시나리오가 있습니다. 예를 들어, React가 파이버 트리를 순회하여 패시브 이펙트(예: useEffect()
)를 마운트하는 방법은 다음과 같습니다(소스).
export function commitPassiveMountEffects(
root: FiberRoot,
finishedWork: Fiber
): void {
nextEffect = finishedWork;
commitPassiveMountEffects_begin(finishedWork, root);
}
function commitPassiveMountEffects_begin(subtreeRoot: Fiber, root: FiberRoot) {
while (nextEffect !== null) {
const fiber = nextEffect;
const firstChild = fiber.child;
if ((fiber.subtreeFlags & PassiveMask) !== NoFlags && firstChild !== null) {
ensureCorrectReturnPointer(firstChild, fiber);
nextEffect = firstChild;
} else {
commitPassiveMountEffects_complete(subtreeRoot, root);
}
}
}
function commitPassiveMountEffects_complete(
subtreeRoot: Fiber,
root: FiberRoot
) {
while (nextEffect !== null) {
const fiber = nextEffect;
if ((fiber.flags & Passive) !== NoFlags) {
setCurrentDebugFiberInDEV(fiber);
try {
commitPassiveMountOnFiber(root, fiber);
} catch (error) {
reportUncaughtErrorInDEV(error);
captureCommitPhaseError(fiber, fiber.return, error);
}
resetCurrentDebugFiberInDEV();
}
if (fiber === subtreeRoot) {
nextEffect = null;
return;
}
const sibling = fiber.sibling;
if (sibling !== null) {
ensureCorrectReturnPointer(sibling, fiber.return);
nextEffect = sibling;
return;
}
nextEffect = fiber.return;
}
}
React는 begin()
과 complete()
로 각 노드를 두 번 밟기 때문에, 캡처와 버블 단계가 있는 DOM 이벤트라고 생각하면 되고, begin()
은 capture
단계, complete()
는 bubble
단계라고 생각하면 됩니다.
부모 파이버 노드가 먼저 begin()
되지만 자식보다 나중에 complete()
됩니다.
이 접근 방식은 begin
과 complete
의 포스트픽스(💬 _begin
이런 형식의 접미사 네이밍) 와 함께 React 소스 코드의 모든 곳에 있으므로, 깊이 빠지기 전에 이 접근 방식에 익숙해져야 합니다.
코딩 챌린지
알고리즘에 대한 이해를 높이기 위해 코딩 챌린지를 준비했습니다. 즐겨보세요!
(원본 게시일: 2022-01-16)