JSX에서
map()으로 만든 배열은 가상돔인가요? Babel은 중첩 구조를 어떻게 처리하나요? 중첩 배열을 그대로 두면 왜 안 되나요?
React.createElement 호출로 번역함 (계층 구조 유지)map()을 쓸 때 발생하며, 이 배열은 가상돔이 아님createElement() 내부에서 이를 평탄화하여 가상돔 트리에 정규화함JSX 구조:
<div>
<p>
<span>Hello</span>
</p>
</div>
Babel 변환 결과:
React.createElement(
'div',
null,
React.createElement(
'p',
null,
React.createElement('span', null, 'Hello')
)
);
children 세 번째 인자로 들어감map()<ul>
{[<li>1</li>, [<li>2</li>, <li>3</li>], <li>4</li>]}
</ul>
Babel 변환 시:
React.createElement(
'ul',
null,
[
React.createElement('li', null, '1'),
[
React.createElement('li', null, '2'),
React.createElement('li', null, '3')
],
React.createElement('li', null, '4')
]
)
createElement에서 이를 평탄화하여 1차원 배열로 정리함// 평탄화 안 하면 이렇게 복잡해짐
function render(children) {
children.forEach(child => {
if (Array.isArray(child)) {
render(child); // 재귀적으로 호출
} else {
mount(child);
}
});
}
const flatChildren = children.flat(Infinity);
flatChildren.forEach(mount);
createElement에서의 평탄화 처리 방식function createElement(
type: string | Function,
props: HTMLAttributes | null,
...children: (Child | Child[])[]
): Readonly<VNode> {
const { ref, key, ...rest } = props ?? {};
const normalizedChildren: Children = Array.isArray(children)
? (children.flat(Infinity) as Child[])
: null;
flat(Infinity)로 중첩 배열 모두 펼침중첩 배열은 가상돔이 아니며,
createElement가 이를 가상돔으로 변환하는 과정에서 평탄화가 발생합니다. 이 과정을 통해 React는 렌더링, 비교, 업데이트 등 모든 작업을 단순한 규칙에 따라 빠르게 처리할 수 있게 됩니다.
map()으로 생긴 배열은 실제 배열이므로 → 반드시 평탄화 필요createElement 안에서 처리하여 모든 자식을 1차원 가상돔 배열로 정규화이 원칙은 바닐라 JS로 리액트 렌더러를 직접 만들 때도 반드시 따라야 할 핵심입니다.