웹 개발의 핵심은 DOM (Document Object Model) 조작이다. 하지만 React Native(이하 RN)에는 DOM이 아예 존재하지 않는다. document.getElementById 같은 코드는 RN에서 실행 즉시 에러를 뱉는다.
Web (Virtual DOM → Real DOM)
웹에서 React는 Virtual DOM을 계산한 뒤, 브라우저의 DOM Tree(<div>, <span>)로 변환한다. 브라우저는 이 HTML 태그를 해석해서 화면에 픽셀을 그린다.
App (Virtual DOM → Native Widgets)
RN은 Virtual DOM을 계산한 뒤, 이를 운영체제(OS)가 제공하는 진짜 네이티브 컴포넌트로 매핑한다.
ios : <View> 를 작성하면 RN은 ios의 UIView를 생성한다.
Android : <View> 를 작성하면 RN은 Android의 android.view.ViewGroup을 생성한다.
이것이 RN 앱이 웹뷰(WebView) 앱보다 성능이 좋고 '진짜 앱'처럼 느껴지는 이유이다. HTML을 그리는 게 아니라, Java/Kotlin/Swift로 짠 것과 똑같은 UI 객체를 생성하기 때문이다.
이 구조 때문에 웹보다 훨씬 엄격한 규칙(Strict Rules)이 적용된다.
텍스트 렌더링의 배타성
web : <div>안녕하세요</div> (가능)
RN: <View>안녕하세요</View> (불가능 - 에러 발생)
이유 : iOS/Android의 레이아웃 컨테이너(UIView/ViewGroup)는 텍스트 렌더링 능력이 없다. 텍스트는 반드시 텍스트 전용 뷰(UILabel/TextView)에 담겨야 한다. 그래서 RN에서는 무조건 <Text>안녕하세요</Text>여야 한다.
계층 구조의 강제성 : 웹에서는 시멘틱 태그(section, article)를 자유롭게 쓰지만, RN은 제공되는 Core Components(View, Text, Image, ScrollView 등)만 사용해야 네이티브 위젯으로 변환될 수 있다.
"RN은 CSS를 쓴다"는 반은 맞고 반은 틀린 말이다. RN은 내부적으로 Yoga라는 C++로 작성된 레이아웃 엔진을 탑재하고 있다. 이 엔진이 JS로 작성된 스타일 객체를 해석해서 각 OS의 네이티브 레이아웃 수치로 변환해 준다.
웹의 CSS와 비슷해 보이지만, 작동 원리와 지원 범위가 완전히 다르다.
웹 CSS의 핵심인 'Cascading Style Sheets'에서 Cascading(상속)이 RN에는 없다.
/* 부모에게 폰트 색을 주면 자식도 변함 */
.parent { color: red; }
<div class="parent">
<span>나도 빨간색</span>
</div>
<View style={{ backgroundColor: 'red' }}>
<Text>나는 기본색(검정)이야</Text>
</View>
이유 : 네이티브 UI 시스템은 부모의 스타일 속성을 자식에게 물려주는 개념이 없다. 그래서 RN에서는 공통 스타일을 변수(const globalStyle)로 만들어 개별 컴포넌트에 일일이 넣어줘야 한다.
RN에서는 스타일값을 인라인으로 넣어주기보단 Styles heat.creat()로 관리하는 것이 권장된다. 인라인은 랜더링시마다 객체가 매번 생성되어 성능이 저하되지만, 후자는 한번만 생성후 항상 id를 참조하기 때문이다.
Yoga 엔진은 Flexbox를 구현했지만, 모바일 환경에 맞춰 기본값이 다르다.
또한 최근 Yoga 엔진에 CSS Grid 지원이 추가되고 있어, 더 복잡한 레이아웃을 웹처럼 구현 가능해지고 있다.
최신 RN 버전에서 일부 지원하기 시작했지만, 여전히 웹처럼 자유롭지 않다.
borderWidth: 1,
borderColor: 'red',
이렇게 풀어서 써야 하는 경우가 많다. margin: "10px 20px" 같은 문자열 방식은 지원하진 않지만, styles-short같은 라이브러리를 사용하면 가능하다. 또한 marginVertical, marginHorizontal 같은 RN 전용 속성도 사용된다.