Skip to main content

Command Palette

Search for a command to run...

[번역] React 파이버 트리 순회는 어떻게 동작하나요?

React Internals Deep Dive - EP15

Updated
2 min readView as Markdown
[번역] React 파이버 트리 순회는 어떻게 동작하나요?
T

Software engineer for web tech. Interested in sustainable growth as software engineer.

영문 블로그 글을 번역했습니다. 허가를 받으면 시리즈를 이어갈 예정입니다.
원문링크:
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가지 프로퍼티가 있습니다.

  1. child, 이름에 따라 그 자식 파이버.

  2. sibling, 이름에 따라 그 형제 파이버

  3. 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() 됩니다.

이 접근 방식은 begincomplete의 포스트픽스(💬 _begin 이런 형식의 접미사 네이밍) 와 함께 React 소스 코드의 모든 곳에 있으므로, 깊이 빠지기 전에 이 접근 방식에 익숙해져야 합니다.

코딩 챌린지

알고리즘에 대한 이해를 높이기 위해 코딩 챌린지를 준비했습니다. 즐겨보세요!

JSer의 블로그 코딩 챌린지 링크

BFE.dev의 코딩 챌린지 링크

(원본 게시일: 2022-01-16)

React Internals Deep Dive 번역 시리즈

Part 15 of 24

[번역] 리액트 내부 작동원리에 대한 JSer의 시리즈입니다. https://jser.dev/series/react-source-code-walkthrough

Up next

[번역] React 이펙트 훅의 수명주기

React Internals Deep Dive - EP16

More from this blog

프론트엔드는 경계를 다루는 직무가 되어간다

프론트엔드는 원래도 복잡했습니다. 브라우저마다 다른 렌더링, 상태 동기화, 성능, 접근성 — 화면 하나 제대로 만드는 데 신경 쓸 게 늘 많았습니다. 다만 그 복잡함은 대체로 한 방향을 향했습니다. 이 UI를 어떻게 만들까, 상태를 어떻게 관리할까, 클릭하면 무엇이 바뀌어야 할까. 그런데 요즘 질문의 축이 하나 더 늘고 있습니다. 이 UI는 서버에서 먼저

Jul 20, 20266 min read

AI가 코드를 짜는 시대, 나는 리뷰를 못 따라가고 있었다

솔직히 말하면, 요즘 PR을 제때 리뷰하지 못하고 있습니다. 개발 속도는 빨라졌는데 리뷰 속도는 그대로입니다. 예전엔 하루 이틀이면 처리하던 게 이제는 며칠씩 밀립니다. 처음엔 제가 게을러진 탓인가 싶었습니다. 돌아보니 그게 아니었습니다. AI 도구를 쓰면서 코드가 쏟아지는 속도가 달라졌습니다. 한 사람이 만들어내는 코드 양이 예전과 비교가 안 됩니다. P

Mar 18, 20263 min read
AI가 코드를 짜는 시대, 나는 리뷰를 못 따라가고 있었다

테드풀의 한 입 지식

78 posts

가볍게 정리하는 기록들입니다.