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 |