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

> ***영문 블로그 글을 번역했습니다. 허가를 받으면 시리즈를 이어갈 예정입니다.  
> 원문링크:***[https://jser.dev/react/2022/01/16/fiber-traversal-in-react](https://jser.dev/react/2022/01/16/fiber-traversal-in-react)

---

> ***ℹ️***[***React Internals Deep Dive***](https://jser.dev/series/react-source-code-walkthrough.html)***에피소드 15,***[***유튜브에서 제가 설명하는 것***](https://www.youtube.com/watch?v=3nwupG2Joaw&list=PLvx8w9g4qv_p-OS-XdbB3Ux_6DMXhAJC3&index=15)***을 시청해주세요.***
> 
> ***⚠***[***React@18.2.0***](https://github.com/facebook/react/releases/tag/v18.2.0)***기준, 최신 버전에서는 구현이 변경되었을 수 있습니다.***
> 
> ***💬 역자 주석: JSer의 코멘트는 ❗❗로 표시 해뒀습니다.  
> 그 외 주석은 리액트 소스 코드 자체의 주석입니다.  
> ... 은 생략된 코드입니다.***

## Fiber Tree 구조

앞서 설명했듯이, React는 내부적으로 파이버 트리를 유지하며 계속 업데이트합니다. 각 파이버 노드에는 구조를 형성하는 3가지 프로퍼티가 있습니다.

1. `child`, 이름에 따라 그 자식 파이버.
    
2. `sibling`, 이름에 따라 그 형제 파이버
    
3. `return`, (일종의)부모 파이버라고 생각할 수 있습니다.
    

`children`이 없기 때문에, 제가 추측하기로 React 팀은 트리 탐색을 가능한 한 간단하게 처리하고 싶기에, 이 세 가지 프로퍼티는 충분히 잘 작동할 것입니다.

이런 일이 있을 수 있습니다.

[![](https://jser.dev/static/fiber-traversal.png align="left")](https://jser.dev/static/fiber-traversal.png)

## Fiber Tree는 어떻게 순회하는가

파이버 트리를 순회해야 하는 많은 시나리오가 있습니다. 예를 들어, React가 파이버 트리를 순회하여 패시브 이펙트(예: `useEffect()`)를 마운트하는 방법은 다음과 같습니다([소스](https://github.com/facebook/react/blob/e62a8d754548a490c2a3bcff3b420e5eedaf11c0/packages/react-reconciler/src/ReactFiberCommitWork.old.js#L2618)).

```typescript
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 소스 코드의 모든 곳에 있으므로, 깊이 빠지기 전에 이 접근 방식에 익숙해져야 합니다.

## 코딩 챌린지

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

[JSer의 블로그 코딩 챌린지 링크](https://jser.dev/react/2022/01/16/fiber-traversal-in-react#coding-challenge)

[BFE.dev의 코딩 챌린지 링크](https://bigfrontend.dev/open_problem/t4yvsyilro3f4zo397)

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