React.createElement
는 JavaScript가 쓸 수 있는 React의 문법일까?React.createElement는 React가 제공하는 JavaScript API이다.
JSX는 사람이 읽기 쉬운 문법일 뿐이며, Babel 같은 트랜스파일러가 내부적으로 이 JSX를 React.createElement 호출로 변환합니다.
key, ref는 특별한 Prop으로, React 내부에서 처리되기 때문에 컴포넌트 함수에서는 직접 접근할 수 없다.
children은 여는 태그와 닫는 태그 사이의 값이다.
// 컴포넌트
<MyComponent title="Hi" color="blue">Hello</MyComponent>
// 내부적으로 props 객체는 이런 형태이다 ⬇️
{
title: "Hi",
color: "blue",
children: "Hello"
}
가상 DOM(Virtual DOM)에서 효율적인 리렌더링을 위해서이다.
리스트를 렌더링할 때, React는 어떤 항목이 추가/삭제/변경되었는지 알아야 한다,
key를 기준으로 비교(diffing)하기 때문에, 안정적이고 고유한 key를 주면 성능 최적화에 도움이 된다.
React는 어떤 항목이 유지되었는지, 바뀌었는지, 사라졌는지, 새로 생겼는지 판단해야 해.
그 기준이 바로 key야.
{isLogin && <LoginInfo />}
React는 여기서 LoginInfo 하나만 렌더링해.
조건이 바뀌지 않는 한 컴포넌트가 그대로 유지돼.
→ 위치나 순서가 바뀌는 일이 없기 때문에 key가 필요 없어.
<div>
<Header />
<Content />
<Footer />
</div>
이제 React가 "위치"와 "타입"을 기준으로 비교한다는 게 정확히 어떤 의미인지 좀 더 명확해졌을 거야.
이 구조는 항상 같은 순서로 렌더링됨.
React는 이걸 기억하고, 바뀌지 않는다면 이전 컴포넌트를 그대로 재사용함.
→ 고정된 구조니까 key 없이도 안정적으로 비교가 가능해.
사이드 이펙트(Side Effect)는 컴포넌트 렌더링 외의 부가적인 동작을 의미한다.
렌더링 외부에서 발생하며, 컴포넌트의 순수성을 해치는 행위라고도 한다.
예) API 요청, DOM 조작, setTimeout, addEventListener, 콘솔 출력, LocalStorage 접근
React에서는 이런 동작들을 useEffect에 넣어서 명시적으로 처리한다.
렌더링과 분리하기 위해서이다.
React는 상태나 props가 바뀔 때 자동으로 다시 렌더링하는 구조이다.
직접 수정하면 리렌더링도 안 되고 버그의 원인이 된다.
props.title = "Hello" // ❌ React의 업데이트 감지 대상이 아니다.
state.count = 10 // ❌ setState를 써야 리렌더링 된다.
함수의 파라미터 이름은 호이스팅되지 않습니다.
호이스팅은 함수 선언, var, let, const 등에 적용되는 개념이고, 파라미터는 함수 내부의 지역 변수로 생각할 수 있다.
React에서 컴포넌트는 함수나 클래스 형태로 선언된, UI 단위를 정의한 것이다.
JSX를 반드시 리턴하지 않아도 된다.
예, Headless 컴포넌트는 렌더링 없이 로직만 제공한다.
function useToggle() {
const [isOpen, setIsOpen] = useState(false);
const toggle = () => setIsOpen(prev => !prev);
return { isOpen, toggle };
}
Headless 컴포넌트란?
Headless 컴포넌트는 커스텀 훅이야?
예) 1: useToggle 같은 커스텀 훅
예 2: Downshift, Headless UI처럼 상태 관리만 하는 라이브러리 컴포넌트
즉, 화면을 렌더하지 않아도 로직을 추상화한 함수형 컴포넌트는 존재할 수 있다.
네. React 18부터 createRoot를 여러 번 호출해서 여러 개의 React 트리를 만들 수 있다.
const root1 = ReactDOM.createRoot(document.getElementById('root1'));
root1.render(<App1 />);
const root2 = ReactDOM.createRoot(document.getElementById('root2'));
root2.render(<App2 />);
React 18에선 Concurrent Mode(동시성 모드)가 도입되었고, 이에 따라 createRoot를 통해 각 Root마다 독립적인 동시성 제어를 가능하게 했어.
이전에는 ReactDOM.render() 하나만 있었고, 앱 전체가 하나의 동기적 트리였음.
하지만 이제는 다음이 가능함:
각 root마다 별도 hydrate, unmount 제어 가능
💡 요약: createRoot는 더 유연한 렌더링, 동시성 제어, 다중 React 앱 구성을 위해 생긴 새로운 API야.
✅ 동시성 모드(Concurrent Mode)란?
기존의 React는 렌더링이 "한 번에 끝나야" 하는 동기적인 구조였어.
예를 들어 컴포넌트가 렌더되면, 전체 렌더링 작업이 끝날 때까지 브라우저는 멈춘다시피 했어.
즉, 렌더링이 무거우면 → 브라우저가 뚝뚝 끊기는 것처럼 느껴짐.
React 18에서는 이 문제를 해결하기 위해 Concurrent Mode (동시성 모드)를 도입했어.
💡 동시성 모드란?
React가 렌더링 작업을 "쪼개서" 비동기적으로 수행할 수 있도록 만든 기능이야.
렌더링 중간에 더 중요한 작업(예: 사용자 입력)이 들어오면,
지금 하던 렌더링을 잠시 멈추고, 중요한 걸 먼저 처리한 다음,
다시 렌더링 작업을 이어가는 식이야.
마치 운영체제의 스레드 스케줄링처럼 느리거나 무거운 작업을 부드럽게 수행할 수 있게 도와줘.
DOM 노드에 두 번 createRoot() 호출해도 안된다.
이건 같은 DOM 요소에 두 개의 React 트리를 생성하려는 시도이다.
const root1 = ReactDOM.createRoot(document.getElementById('root1'));
root1.render(<App1 />);
const root2 = ReactDOM.createRoot(document.getElementById('root1'));
root2.render(<App2 />);
React는 상태가 바뀌면 전체 렌더링을 "다시 계산"하지만, 실제 브라우저 DOM은 "변경된 부분만 업데이트"함.
그리고 key는 그 "변경된 부분"을 더 정확하게 추적해서 낭비 없이 DOM을 조작하기 위한 도구야.