๐ŸŒฑ <groot/>
React Fiber ํŒŒํ—ค์น˜๊ธฐ โ€” DOM ์š”์†Œ์—์„œ ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ๋กœ ๊ฑฐ์Šฌ๋Ÿฌ ์˜ฌ๋ผ๊ฐ€๊ธฐ | Groot's Tech Blog
โš›๏ธReact

React Fiber ํŒŒํ—ค์น˜๊ธฐ โ€” DOM ์š”์†Œ์—์„œ ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ๋กœ ๊ฑฐ์Šฌ๋Ÿฌ ์˜ฌ๋ผ๊ฐ€๊ธฐ

2026.07.02ยท4๋ถ„ ์ฝ๊ธฐ

์šฐํด๋ฆญ์œผ๋กœ ์ปดํฌ๋„ŒํŠธ ์†Œ์Šค๋กœ ์ ํ”„ํ•˜๋Š” ๋„๊ตฌ๋ฅผ ๋งŒ๋“ค ๋•Œ, ๋Ÿฐํƒ€์ž„์˜ ํ•ต์‹ฌ ์งˆ๋ฌธ์€ ์ด๊ฑฐ์˜€๋‹ค.

์‚ฌ์šฉ์ž๊ฐ€ ํด๋ฆญํ•œ ์ด DOM ์š”์†Œ๊ฐ€, ๋Œ€์ฒด ์–ด๋А React ์ปดํฌ๋„ŒํŠธ์—์„œ ๋‚˜์˜จ ๊ฑธ๊นŒ?

๋ธŒ๋ผ์šฐ์ €์— ์‹ค์ œ๋กœ ์กด์žฌํ•˜๋Š” ๊ฑด <div>, <button> ๊ฐ™์€ DOM ๋…ธ๋“œ๋ฟ์ด๋‹ค. React ์ปดํฌ๋„ŒํŠธ๋Š” ๋ Œ๋”๋ง์ด ๋๋‚˜๋ฉด ์‚ฌ๋ผ์ง„ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค. ํ•˜์ง€๋งŒ React๋Š” ๊ทธ ์—ฐ๊ฒฐ๊ณ ๋ฆฌ๋ฅผ DOM์— ๋ชฐ๋ž˜ ๋งค๋‹ฌ์•„ ๋‘”๋‹ค. ๊ทธ๊ฒŒ Fiber๋‹ค. ์ด ๊ธ€์€ Fiber๋ฅผ ํŒŒ๊ณ ๋“ค์–ด "DOM โ†’ ์ปดํฌ๋„ŒํŠธ"๋ฅผ ๋˜์งš๋Š” ๋ฐฉ๋ฒ•์„ ์ •๋ฆฌํ•œ๋‹ค.

Fiber๊ฐ€ ๋ญ”๊ฐ€ (์•„์ฃผ ์งง๊ฒŒ)

React 16๋ถ€ํ„ฐ ๋‚ด๋ถ€ ๋ Œ๋”๋ง ๋‹จ์œ„๋Š” Fiber๋ผ๋Š” ๊ฐ์ฒด๋‹ค. ์ปดํฌ๋„ŒํŠธ ํ•˜๋‚˜, JSX ์š”์†Œ ํ•˜๋‚˜๊ฐ€ ๊ฐ๊ฐ Fiber ๋…ธ๋“œ๊ฐ€ ๋˜๊ณ , ์ด๋“ค์ด ํŠธ๋ฆฌ๋ฅผ ์ด๋ฃฌ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ํŠธ๋ฆฌ๋ฅผ ๊ฑฐ์Šฌ๋Ÿฌ ์˜ฌ๋ผ๊ฐˆ ๋•Œ ์“ธ ํ•„๋“œ๋Š” ์ด ์ •๋„๋‹ค.

  • return โ€” ๋ถ€๋ชจ Fiber (ํŠธ๋ฆฌ๋ฅผ ์œ„๋กœ ์˜ฌ๋ผ๊ฐˆ ๋•Œ ์“ด๋‹ค)
  • type / elementType โ€” ์ด Fiber๊ฐ€ ๋ฌด์—‡์ธ๊ฐ€. ํ˜ธ์ŠคํŠธ ์š”์†Œ๋ฉด "div" ๊ฐ™์€ ๋ฌธ์ž์—ด, ์ปดํฌ๋„ŒํŠธ๋ฉด ๊ทธ ํ•จ์ˆ˜/ํด๋ž˜์Šค ์ž์ฒด
  • pendingProps / memoizedProps โ€” ์ด ์š”์†Œ์˜ props
  • _debugSource โ€” (React 18๊นŒ์ง€) ์›๋ณธ ์†Œ์Šค ์œ„์น˜. React 19์—์„œ ์ œ๊ฑฐ๋จ

1. DOM ์š”์†Œ์—์„œ Fiber ๊บผ๋‚ด๊ธฐ

React๋Š” DOM ๋…ธ๋“œ์— __reactFiber$โ€ฆ(๋˜๋Š” ์˜› ๋ฒ„์ „์€ __reactInternalInstance$โ€ฆ)๋ผ๋Š” ๋žœ๋ค ์ ‘๋ฏธ์‚ฌ๊ฐ€ ๋ถ™์€ ํ‚ค๋กœ Fiber๋ฅผ ๋งค๋‹ฌ์•„ ๋‘”๋‹ค. ์ ‘๋ฏธ์‚ฌ๊ฐ€ ๋งค๋ฒˆ ๋ฐ”๋€Œ๋‹ˆ, ํ‚ค ์ด๋ฆ„์„ ์ง์ ‘ ํ•˜๋“œ์ฝ”๋”ฉํ•  ์ˆ˜ ์—†๊ณ  ์ฐพ์•„์•ผ ํ•œ๋‹ค.

const fiberKeyCache = new WeakMap<Element, string | undefined>();

function getReactFiberKey(element: Element) {
  if (fiberKeyCache.has(element)) return fiberKeyCache.get(element);
  const key = Object.keys(element).find(
    (k) => k.startsWith("__reactFiber$") ||
           k.startsWith("__reactInternalInstance$"),
  );
  fiberKeyCache.set(element, key); // ์ ‘๋ฏธ์‚ฌ๋Š” ์„ธ์…˜ ๋‚ด ๊ณ ์ • โ†’ ์บ์‹œ
  return key;
}

Object.keys(element)๋กœ ํ‚ค๋ฅผ ๋’ค์ง€๋Š” ๊ฑด ๊ณต์งœ๊ฐ€ ์•„๋‹ˆ๋ผ์„œ WeakMap์— ์บ์‹œํ–ˆ๋‹ค. WeakMap์ด๋ผ ์š”์†Œ๊ฐ€ ์‚ฌ๋ผ์ง€๋ฉด ์บ์‹œ๋„ ์ž๋™์œผ๋กœ ์ •๋ฆฌ๋œ๋‹ค.

ํด๋ฆญํ•œ ์š”์†Œ์— Fiber๊ฐ€ ์—†์„ ์ˆ˜๋„ ์žˆ๋‹ค(ํ…์ŠคํŠธ ๋…ธ๋“œ๋‚˜ ์ˆœ์ˆ˜ DOM). ๊ทธ๋Ÿด ๋• ๋ถ€๋ชจ๋กœ ํ•œ ์นธ์”ฉ ์˜ฌ๋ผ๊ฐ€๋ฉฐ Fiber๋ฅผ ๊ฐ€์ง„ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ์š”์†Œ๋ฅผ ์ฐพ๋Š”๋‹ค.

function getClosestReactFiber(target: Element | null) {
  let current = target;
  while (current) {
    const fiberKey = getReactFiberKey(current);
    if (fiberKey) {
      return (current as any)[fiberKey] as ReactFiber;
    }
    current = current.parentElement;
  }
  return null;
}

2. Fiber ํŠธ๋ฆฌ๋ฅผ ๊ฑฐ์Šฌ๋Ÿฌ ์˜ฌ๋ผ๊ฐ€๋ฉฐ ์†Œ์Šค ์ฐพ๊ธฐ

Fiber ํ•˜๋‚˜๋ฅผ ์žก์•˜์œผ๋ฉด, ์ด์ œ return(๋ถ€๋ชจ)์„ ๋”ฐ๋ผ ์œ„๋กœ ์˜ฌ๋ผ๊ฐ€๋ฉด์„œ ๋นŒ๋“œ ํƒ€์ž„์— ์‹ฌ์–ด๋‘” ์†Œ์Šค ์ •๋ณด๋ฅผ ๋ชจ์€๋‹ค. ์ •๋ณด๋Š” ๋‘ ๊ตฐ๋ฐ์— ์žˆ๋‹ค.

  • ์ปดํฌ๋„ŒํŠธ ์ชฝ: fiber.type/elementType(= ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜)์— ๋ถ™์—ฌ๋‘” __componentSourceLoc
  • JSX ์š”์†Œ ์ชฝ: props ์•ˆ์— ๋„ฃ์–ด๋‘” $componentSourceLoc
function getSourceFromType(type: unknown) {
  if (typeof type === "function") {
    // ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜์— ๋ถ™์—ฌ๋‘” ์†Œ์Šค ์œ„์น˜
    const source = (type as any).__componentSourceLoc;
    return typeof source === "string" ? source : null;
  }
  // memo/forwardRef ๋กœ ๊ฐ์‹ธ์ง€๋ฉด type์ด ๊ฐ์ฒด๋ผ, ํ•œ ๊ฒน ๋” ๋“ค์–ด๊ฐ€ ๋ณธ๋‹ค
  if (type && typeof type === "object") {
    const t = type as any;
    return t.__componentSourceLoc
        ?? t.type?.__componentSourceLoc      // memo(...)
        ?? t.render?.__componentSourceLoc    // forwardRef(...)
        ?? null;
  }
  return null;
}

์—ฌ๊ธฐ์„œ ์žฌ๋ฏธ์žˆ๋Š” ์ง€์ : memo(Comp)๋‚˜ forwardRef(Comp)๋Š” type์ด ํ•จ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ๊ฐ์ฒด๋‹ค. memo๋Š” .type์—, forwardRef๋Š” .render์— ์‹ค์ œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋“ค์–ด ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ ํ•œ ๊ฒน์”ฉ ๋” ๋“ค์—ฌ๋‹ค๋ด์•ผ ์†Œ์Šค๋ฅผ ๋†“์น˜์ง€ ์•Š๋Š”๋‹ค. ์ด๋Ÿฐ ๋ž˜ํ•‘ ์ผ€์ด์Šค๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒŒ ์‹ค์ „์—์„œ ์ œ์ผ ์†์ด ๋งŽ์ด ๊ฐ”๋‹ค.

3. "ํ™”๋ฉด ์œ„์น˜"์™€ "๊ตฌํ˜„ ์œ„์น˜"๋Š” ๋‹ค๋ฅด๋‹ค

ํŠธ๋ฆฌ๋ฅผ ์˜ฌ๋ผ๊ฐ€๋‹ค ๋ณด๋ฉด ์†Œ์Šค ํ›„๋ณด๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ ๋‚˜์˜จ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋””์ž์ธ ์‹œ์Šคํ…œ์˜ <Button>์„ ํด๋ฆญํ•˜๋ฉด:

  • ๋‚ด๊ฐ€ <Button>์„ ์“ด ์ž๋ฆฌ (์˜ˆ: CheckoutPage.tsx:42) โ€” ํ™”๋ฉด(screen)
  • Button์ด ์ •์˜๋œ ์ž๋ฆฌ (์˜ˆ: node_modules/ui/Button.tsx) โ€” ๊ตฌํ˜„(implementation)

๋””์ž์ธ์„ ๊ณ ์น˜๋ ค๋Š” ์‚ฌ๋žŒ์€ ๋ณดํ†ต ๋‚ด๊ฐ€ ์“ด ์ž๋ฆฌ๋ฅผ ์›ํ•œ๋‹ค. ๊ทธ๋ž˜์„œ ํ›„๋ณด๋“ค์„ ๋ชจ์€ ๋’ค, "ํ”„๋กœ์ ํŠธ ๋กœ์ปฌ(๋‚ด ์ฝ”๋“œ)์ธ์ง€"๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํ™”๋ฉด์šฉ/๊ตฌํ˜„์šฉ์„ ๋‚˜๋ˆด๋‹ค.

// ๋‚ด ํ”„๋กœ์ ํŠธ ์•ˆ์˜ ์†Œ์Šค์ธ๊ฐ€? (node_modulesยท์ƒ์œ„ ๊ฒฝ๋กœ๋ฉด ์ œ์™ธ)
const isLocal = (source) => isProjectLocalSource(source, projectRoot);

// screen: ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ํ”„๋กœ์ ํŠธ ๋กœ์ปฌ ์œ„์น˜
// implementation: ํ”„๋กœ์ ํŠธ ์™ธ๋ถ€(๊ณต์œ  ์ปดํฌ๋„ŒํŠธ) ์œ„์น˜

Alt+1(screen) / Alt+2(implementation)๋กœ ๋ชจ๋“œ๋ฅผ ํ† ๊ธ€ํ•˜๊ฒŒ ๋งŒ๋“  ์ด์œ ๊ฐ€ ์ด๊ฑฐ๋‹ค. ๊ฐ™์€ ํ”ฝ์…€์„ ํด๋ฆญํ•ด๋„ "์ •๋‹ต ์†Œ์Šค"๊ฐ€ ํ•˜๋‚˜๊ฐ€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

_debugSource์— ๊ธฐ๋Œ€์ง€ ์•Š๊ธฐ๋กœ ํ•œ ์ด์œ 

์˜ˆ์ „์—” ์ด ๋ชจ๋“  ๊ฑธ fiber._debugSource ํ•˜๋‚˜๋กœ ๋Œ€์ถฉ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. React๊ฐ€ ๊ฐœ๋ฐœ ๋ชจ๋“œ์—์„œ ์›๋ณธ ์œ„์น˜๋ฅผ ๋ถ™์—ฌ์คฌ์œผ๋‹ˆ๊นŒ. ๊ทธ๋Ÿฐ๋ฐ React 19์—์„œ ์ด๊ฒŒ ๋น ์กŒ๋‹ค.

๊ทธ๋ž˜์„œ ๋ฐฉํ–ฅ์„ ๋ฐ”๊ฟจ๋‹ค. React๊ฐ€ ์ฃผ๋Š” ๊ฑธ ์“ฐ๋Š” ๋Œ€์‹ , ๋‚ด๊ฐ€ ๋นŒ๋“œ ํƒ€์ž„์— ์ง์ ‘ __componentSourceLoc/$componentSourceLoc๋ฅผ ์‹ฌ๊ณ , ๋Ÿฐํƒ€์ž„์— Fiber๋ฅผ ๋’ค์ ธ ๊ทธ๊ฑธ ์ฝ๋Š”๋‹ค. ์ฝ”๋“œ๋Š” ์ด legacy ํ•„๋“œ๋„ ํด๋ฐฑ์œผ๋กœ ํ•จ๊ป˜ ์ง€์›ํ•œ๋‹ค.

const raw =
  getSourceFromProps(fiber.pendingProps) ??
  getSourceFromProps(fiber.memoizedProps) ??
  getDirectDebugSource(fiber);   // _debugSource ํด๋ฐฑ (React โ‰ค18)

๊ฒฐ๊ณผ์ ์œผ๋กœ React ๋ฒ„์ „์— ๋…๋ฆฝ์ ์ธ ๋” ํŠผํŠผํ•œ ๊ตฌ์กฐ๊ฐ€ ๋๋‹ค. ํ”„๋ ˆ์ž„์›Œํฌ ๋‚ด๋ถ€ ๊ตฌํ˜„์— ์˜์กดํ•  ๋•Œ์˜ ์œ„ํ—˜(์–ด๋А ๋‚  ์กฐ์šฉํžˆ ์‚ฌ๋ผ์ง„๋‹ค)์„ ์ •๋ฉด์œผ๋กœ ๋ฐฐ์šด ์‚ฌ๋ก€์˜€๋‹ค.

์ •๋ฆฌ

  • React๋Š” DOM ๋…ธ๋“œ์— __reactFiber$โ€ฆ ํ‚ค๋กœ Fiber๋ฅผ ๋งค๋‹ฌ์•„ ๋‘”๋‹ค.
  • getClosestReactFiber โ†’ fiber.return์œผ๋กœ ํŠธ๋ฆฌ๋ฅผ ์œ„๋กœ ์ˆœํšŒํ•˜๋ฉด DOM์—์„œ ์ปดํฌ๋„ŒํŠธ ๊ณ„๋ณด๋ฅผ ๋˜์งš์„ ์ˆ˜ ์žˆ๋‹ค.
  • type/elementType์—์„œ ์ปดํฌ๋„ŒํŠธ๋ฅผ, props์—์„œ JSX ์š”์†Œ ์†Œ์Šค๋ฅผ ์ฝ๋Š”๋‹ค. memo/forwardRef๋Š” ํ•œ ๊ฒน ๋” ๋“ค์–ด๊ฐ€์•ผ ํ•œ๋‹ค.
  • ๊ฐ™์€ UI๋ผ๋„ ํ™”๋ฉด ์œ„์น˜ โ‰  ๊ตฌํ˜„ ์œ„์น˜. ๋‘˜ ๋‹ค ํ•„์š”ํ•˜๋‹ค.

Fiber๋Š” "React๊ฐ€ ๋ Œ๋”๋ง์„ ์–ด๋–ป๊ฒŒ ๊ธฐ์–ตํ•˜๋Š”๊ฐ€"์˜ ์‹ค์ฒด๋‹ค. ํ•œ ๋ฒˆ ์—ด์–ด๋ณด๋ฉด DevTools๊ฐ€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€, ์™œ ๊ทธ๋Ÿฐ ์ œ์•ฝ์ด ์žˆ๋Š”์ง€๊ฐ€ ์ „๋ถ€ ๋ณด์ธ๋‹ค.

โ† ๋ชฉ๋ก์œผ๋กœ ๋Œ์•„๊ฐ€๊ธฐ
ยฉ 2026 ยท Groot's Tech Blog. Built with Gatsby ๐ŸŒฑ