React Core 구현하기 - 2. JSX 런타임 로직

2025. 2. 18. 12:41·React

JSX 런타임은 트랜스파일러가 생성한 JSX 객체를 VDOM으로 변환하는 역할을 합니다.

JSX 런타임 로직 구현

JSX 트랜스파일을 위한 설정이 완료되었다면, 트랜스파일러가 사용할 JSX 변환 로직을 구현합니다.

파일명은 jsx-dev-runtime.ts으로 생성합니다. 이는 트랜스파일 설정에서 runtime: "automatic" 시 기본적으로 해당 파일명을 찾기 때문입니다.(prod 환경에서는 jsx-runtime.ts를 사용하지만 이 프로젝트에서는 사용하지 않습니다.)

 

 

기본 구조

// jsx-dev-runtime.ts
const flattenChildren = (children?: TVDOMType): TVDOMType[] => {
  ...
};

export const jsxDEV = (type: TVDOMType, props: TVDOMProps) => {
  ...
};

export const jsxsDEV = (...args: Parameters<typeof jsxDEV>) => {
  ...
}

jsx-dev-runtime.ts 파일은 다음과 같은 구성으로 작성했습니다.

아래 내용은 각 함수들에 대한 설명입니다.

 

jsxDev

자식 요소가 없거나 하나일 때 사용되며, JSX가 자바스크립트 객체로 트랜스파일되어  VDOM으로 사용됩니다.
child의 유형에 따라 3가지 유형으로 변환됩니다.

  • User Defined: 사용자가 정의한 컴포넌트 함수
  • Intrinsic: HTML태그와 같은 내장 요소
  • Primitive: 텍스트노드 또는 조건부렌더링의 결과물(boolean)
export const jsxDEV = (type: TVDOMType, props: TVDOMProps) => {
  const propsWithFlattenedChildren = {
    ...props,
    children: flattenChildren(props.children),
  };
  return {
    type,
    props: propsWithFlattenedChildren,
  };
};

 

jsxsDev

다중 자식 요소를 처리하기 위한 함수이며, jsxDev와 완전하게 동일하게 동작합니다.
Babel은 다중 자식요소를 처리할때 jsxsDev 함수를 따로 구분하여 사용하므로 중복되더라도 따로 구현을 해주어야 했습니다.

export function jsxsDEV(...args: Parameters<typeof jsxDEV>) {
  return jsxDEV(...args);
}

 

flattenChildren

조건부 렌더링 등으로 불필요한 배열 중첩이 발생하는 구조의 렌더링 최적화를 위해 평탄화 작업을 진행합니다.

const flattenChildren = (children?: TVDOMType): TVDOMType[] => {
  if (children == null) return [];
  if (Array.isArray(children)) {
    return children
    // 재귀를 통해 소속된 모든 자녀를 평탄화, undefined or null인 요소는 VDOM에서 제외
      .flatMap((child) => flattenChildren(child))
      .filter((child) => child != null);
  }
  return [children];
};

 

평탄화 유 / 무를 생성된 VDOM을 통해 확인해 봅니다.

// --- 변환 전 jsx
<div>
  <span>Hello</span>
  {items.map(item => <Item key={item.id} {...item} />)}
</div>

// --- 평탄화하지 않은 VDOM
{
  type: "div",
  props: {
    // 불필요한 배열 중첩이 발생
    children: [
      { type: "span", props: { children: "Hello" } },
      [
        { type: Item, props: { key: "1", ...item1 } },
        { type: Item, props: { key: "2", ...item2 } }
      ],
    ]
  }
}

// --- 평탄화를 진행한 VDOM
{
  type: "div",
  props: {
    // 불필요한 배열 중첩이 제거됨
    children: [
      { type: "span", props: { children: "Hello" } },
      { type: Item, props: { key: "1", ...item1 } },
      { type: Item, props: { key: "2", ...item2 } },
    ]
  }
}

 

저작자표시 비영리 변경금지 (새창열림)

'React' 카테고리의 다른 글

React 컴포넌트가 순수해야 하는 이유  (0) 2025.07.04
Zustand 셀렉터... 사용하고 계시죠? (리렌더 폭탄 방지하기)  (0) 2025.06.20
React Core 구현하기 - 1. JSX 컴파일  (0) 2025.02.14
React18 useEffectEvent  (0) 2024.12.30
React useLayoutEffect  (2) 2024.12.27
'React' 카테고리의 다른 글
  • React 컴포넌트가 순수해야 하는 이유
  • Zustand 셀렉터... 사용하고 계시죠? (리렌더 폭탄 방지하기)
  • React Core 구현하기 - 1. JSX 컴파일
  • React18 useEffectEvent
URE
URE
Skill: Javascript, ReactJS, Next.js, React Native ... *블로그 이전 작업(24. 04. 11 ~ 24. 04. 15)
  • URE
    Dev++
    URE
  • 전체
    오늘
    어제
    • 분류 전체보기 (51)
      • Browser (6)
      • OS (1)
      • Javascript (14)
      • React (19)
      • Next.js (4)
      • React Native (0)
      • Architecture (1)
      • Network (3)
      • 스크랩 (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    상태관리라이브러리
    리액트 코어
    javascript
    react18
    IP
    브라우저
    리덕스
    Redux
    URL
    dataFetching
    TCP
    Port
    원시타입
    react
    리액트
    react concurrent
    JS
    참조타입
    자바스크립트
    swr
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
URE
React Core 구현하기 - 2. JSX 런타임 로직
상단으로

티스토리툴바