"RN은 네이티브 뷰를 JS로 제어한다 — Bridge는 그 둘을 잇던 비동기 큐, JSI는 직접 통하는 C++ 다리다"
"RN으로 앱을 만드는 것과, JS와 네이티브가 어떤 경계로 통신하고 그 경계가 어떻게 진화했는지 아는 것은 다르다"
구형 Bridge의 직렬화 비동기 큐에서 JSI·Fabric·TurboModules의 직접 호출로 옮겨가는 과정과, Hermes 바이트코드가 모바일 시작 비용을 어떻게 0에 가깝게 만드는지 — 왜 이렇게 동작하는가 라는 질문으로 React Native의 두 세계 경계를 끝까지 파헤칩니다
RN 자료는 넘쳐납니다. 하지만 대부분은 "어떻게 쓰나" 에서 멈춥니다.
| 일반 자료 | 이 레포 |
|---|---|
| "RN은 JS로 만드는 네이티브 앱입니다" | JS 스레드에서 돌아가는 React 트리가 어떤 경계를 거쳐 UIView/android.View가 되는지, 스레드 모델과 메시지 흐름을 직접 추적 |
| "Bridge가 New Architecture로 바뀌었습니다" | 구형 Bridge의 JSON 직렬화 비동기 큐가 어떤 호출 패턴에서 병목이 되는지, JSI가 그것을 어떻게 동기 직접 호출로 대체하는지 코드로 비교 |
| "Fabric은 새 렌더러입니다" | C++ Shadow Tree가 React Fiber 트리와 어디에서 만나는가, Yoga 레이아웃이 동기 측정을 가능하게 하는 메커니즘 |
| "TurboModules는 더 빠릅니다" | 구형 NativeModules의 직렬화 비용이 어디서 발생하는지, Codegen이 타입 안전한 JSI 바인딩을 어떻게 생성하는지 |
| "Hermes는 RN에 최적화되어 있습니다" | 빌드 타임에 .hbc 바이트코드를 사전 생성해 파싱·JIT 시작 비용을 제거하는 원리, V8 JIT 전략과의 트레이드오프 |
| "큰 데이터는 Bridge로 보내지 마세요" | 동일 페이로드를 Bridge vs JSI로 반복 전송하며 경계 비용을 직접 측정, 무엇을 네이티브로 보낼지에 대한 정량적 기준 |
| 이론 나열 | 실행 가능한 코드 + Flipper/React DevTools + TurboModule 작성 + Old/New Architecture 같은 화면 실측 비교 |
선행 학습 권장: React Internals Deep Dive — Fiber와 재조정이 Fabric의 입력. Android Framework Internals / UIKit · Core Animation — 네이티브 뷰가 RN의 출력.
각 챕터의 첫 문서부터 바로 학습을 시작하세요!
💡 각 섹션을 클릭하면 상세 문서 목록이 펼쳐집니다
핵심 질문: JS로 작성한 트리는 어떤 스레드에서 살고, 어떻게 진짜 네이티브 뷰가 되는가?
두 세계의 분업, 스레드 모델, 렌더 흐름, Old vs New 미리보기까지 (5개 문서)
| 문서 | 다루는 내용 |
|---|---|
| 01. React Native란 | "JS로 네이티브 뷰를 제어"의 의미 — 웹뷰가 아닌 진짜 UIView/android.View, Flutter의 자체 렌더와 본질적으로 다른 지점 |
| 02. 스레드 모델 | JS 스레드·Main(UI) 스레드·Shadow 스레드의 분업과 소유권, 각 스레드가 무엇을 할 수 있고 무엇을 할 수 없는가 |
| 03. 두 세계 | JS 세계(React 트리·이벤트 핸들러)와 네이티브 세계(뷰 트리·렌더 파이프라인)의 분리, 경계가 곧 비용이라는 명제 |
| 04. 렌더 흐름 한눈에 | React 트리 → Shadow Tree → 네이티브 뷰 마운트의 단계, 어느 스레드에서 무엇이 일어나는지 한 장 다이어그램으로 |
| 05. Old vs New Architecture | Bridge(직렬화 비동기) → JSI(직접 동기)로의 전환 미리보기, Fabric·TurboModules가 함께 바뀌는 이유 |
핵심 질문: Bridge는 왜 "느리다"고 불리는가? 정확히 어디서 비용이 발생하는가?
JSON 직렬화 큐, 3스레드 흐름, 동기 측정 불가의 정체까지 (5개 문서)
| 문서 | 다루는 내용 |
|---|---|
| 01. Bridge 구조 | JS와 네이티브 사이의 비동기 메시지 큐, MessageQueue/RCTBridge의 실체, 양방향 통신이 따르는 패턴 |
| 02. 직렬화 통신 | 모든 호출이 JSON 직렬화 → 큐 → 역직렬화를 거치는 흐름, 큰 페이로드에서 누적되는 비용 |
| 03. Bridge의 한계 | 직렬화 비용·비동기 강제·배치 지연 — 동기 측정이 불가능해서 생기는 레이아웃 깜빡임과 제스처 끊김 |
| 04. 3스레드 흐름 | JS → Shadow(레이아웃) → Main(렌더)으로 비동기 3단 점프하는 흐름, 각 단계에서 보존되는 컨텍스트 |
| 05. 왜 느린가 | 스크롤 동기화·제스처·애니메이션이 끊기는 구체적 시나리오, 통신량과 응답성의 관계를 측정으로 확인 |
핵심 질문: JSI는 어떻게 직렬화 없이 JS와 C++을 직접 잇는가?
동기 호출, HostObject, 엔진 독립 설계까지 (6개 문서)
| 문서 | 다루는 내용 |
|---|---|
| 01. JSI란 | JavaScript Interface — JS 엔진에 C++로 직접 접근하는 얇은 추상화 계층, Bridge를 대체하는 것이 아니라 제거하는 설계 |
| 02. 동기 호출 | 직렬화 없이 JS↔C++ 함수가 같은 스레드에서 직접 호출되는 메커니즘, Bridge에서 불가능했던 동기 측정의 부활 |
| 03. HostObject | JS에서 보이는 C++ 객체의 정체 — get/set 가로채기로 메서드를 동적으로 노출, JS 측 프록시와의 차이 |
| 04. 엔진 독립 설계 | JSI가 JSC/Hermes/V8 어디에도 묶이지 않는 이유, 엔진 교체 비용을 RN 코어에서 분리한 추상화의 가치 |
| 05. 메모리와 생명주기 | JSI 객체의 소유권 모델, JS GC와 C++ 수동 관리의 경계, weak/strong reference 관리의 실수 패턴 |
| 06. Bridge → JSI 비교 | 같은 호출을 Bridge와 JSI로 보내며 직렬화 비용·비동기 강제·지연을 정량 비교, 어느 패턴에서 차이가 큰가 |
핵심 질문: React Fiber 트리는 어떻게 진짜 네이티브 뷰로 마운트되는가?
C++ Shadow Tree, Fiber 연결, Yoga, 동시성까지 (6개 문서)
| 문서 | 다루는 내용 |
|---|---|
| 01. Fabric 개요 | 새 렌더 시스템의 C++ 코어, React와 네이티브를 통합하는 단일 파이프라인, 구형 UIManager와의 구조 차이 |
| 02. C++ Shadow Tree | 레이아웃 트리가 C++ 객체로 표현되어 iOS·Android에서 공유되는 구조, 불변 트리로 가능해진 concurrent rendering |
| 03. React Fiber와 연결 | react-internals의 Fiber가 Shadow Node로 매핑되는 경로, render 결과가 어떤 C++ 호출로 이어지는가 |
| 04. 렌더 파이프라인 | render → commit → mount 3단계, 동기 측정이 가능해진 시점, 레이아웃-페인트의 책임 분담 |
| 05. Yoga 레이아웃 | C++로 작성된 Flexbox 엔진, 웹·iOS·Android에 일관된 레이아웃을 보장하는 동기 측정 API |
| 06. 동시성과 우선순위 | React 18 동시성 모드가 Fabric에서 어떻게 살아나는가, 우선순위 기반 인터럽트의 네이티브 측 구현 |
핵심 질문: 네이티브 모듈이 JSI 위에 올라타면 무엇이 달라지는가?
지연 로딩, Codegen, 모듈 작성, 경계 비용까지 (5개 문서)
| 문서 | 다루는 내용 |
|---|---|
| 01. TurboModules | JSI 기반 네이티브 모듈 — 지연 로딩과 동기 호출, 앱 시작 시 모든 모듈을 미리 로드하던 구형 패턴과의 결별 |
| 02. NativeModules 비교 | 구형 Bridge 기반 NativeModules vs JSI 기반 TurboModules의 호출 경로·시그니처·비용 비교 |
| 03. Codegen | TypeScript Spec → C++/Java/Obj-C 인터페이스 자동 생성, 타입 불일치를 빌드 타임에 잡는 메커니즘 |
| 04. 네이티브 모듈 작성 | Android(Kotlin)와 iOS(Swift)로 TurboModule을 직접 작성, 경계를 어디에 그을지에 대한 설계 결정 |
| 05. 경계 비용 | JSI에서도 여전히 존재하는 호출당 오버헤드, 큰 데이터를 어떻게 다룰지(ArrayBuffer·shared memory) 결정 기준 |
핵심 질문: Hermes는 어떻게 모바일 앱 시작 시간을 거의 0으로 만드는가?
바이트코드 사전 컴파일, V8 비교, 모바일 GC까지 (5개 문서)
| 문서 | 다루는 내용 |
|---|---|
| 01. Hermes란 | RN 전용 경량 JS 엔진의 설계 목표 — JIT를 포기하고 시작 비용과 메모리를 우선한 모바일 최적화 |
| 02. 바이트코드 사전 컴파일 | 빌드 타임에 .hbc 바이트코드를 생성해 앱 번들에 포함, 런타임 파싱·컴파일 비용을 제거하는 흐름 |
| 03. V8과 비교 | V8의 JIT 계층(Ignition·TurboFan) vs Hermes의 AOT 바이트코드 전용 — 시작·메모리·정상상태 처리량의 트레이드오프 |
| 04. 메모리와 GC | 모바일 제약(작은 힙·앱 일시정지 시 swap)에 맞춘 세대 GC, V8의 incremental marking과의 설계 차이 |
| 05. 디버깅 | Hermes 디버거 + Chrome DevTools 프로토콜, 바이트코드 수준 추적, 프로덕션에서도 켤 수 있는 sampling profiler |
핵심 질문: 같은 화면을 Old/New Architecture로 만들면 얼마나 다른가?
측정 도구, 흔한 병목, 마이그레이션, 종합 비교까지 (4개 문서)
| 문서 | 다루는 내용 |
|---|---|
| 01. 성능 측정 | Flipper · React DevTools · Systrace · Instruments를 경계별로 분리해서 보는 법, JS 스레드 vs 네이티브 추적 |
| 02. 흔한 병목 | 과한 Bridge/JSI 호출, 큰 리스트(FlatList vs FlashList), 이미지 디코딩 — 각 병목의 측정 방법과 회피 패턴 |
| 03. New Architecture 마이그레이션 | 기존 RN 앱을 New Architecture로 점진 전환, interop 레이어가 보장하는 호환성과 깨지는 지점 |
| 04. 종합 — Old vs New 실측 | 같은 화면(리스트·애니메이션·제스처)을 Old와 New로 직접 측정, p50/p99/메모리/시작 시간 비교 |
🟢 "Bridge가 왜 느리고 JSI가 무엇을 바꾸는가" 정확히 알고 싶다 — 면접/실무 의문 해소 (2주)
Week 1 — 두 세계와 구형 Bridge
Ch1-02 스레드 모델
Ch1-03 두 세계
Ch2-01 Bridge 구조
Ch2-02 직렬화 통신
Ch2-05 왜 느린가
Week 2 — JSI로의 전환
Ch3-01 JSI란
Ch3-02 동기 호출
Ch3-06 Bridge → JSI 비교
Ch5-01 TurboModules
Ch7-04 Old vs New 실측
🔵 RN 내부를 원리로 이해하고 싶은 개발자 (7주)
Week 1 Chapter 1 전체 — 아키텍처 개요와 스레드 모델
Week 2 Chapter 2 전체 — 구형 Bridge의 한계
Week 3 Chapter 3 전체 — JSI 기반
Week 4 Chapter 4 전체 — Fabric 렌더러
Week 5 Chapter 5 전체 — TurboModules와 네이티브 모듈
Week 6 Chapter 6 전체 — Hermes 엔진
Week 7 Chapter 7 전체 — 성능과 실전 비교
🔴 네이티브 모듈을 작성하는 개발자의 집중 코스
핵심 경로 (Android/iOS 어느 쪽이든 적용 가능)
Step 1 Ch1-02~03 스레드 소유권과 두 세계
Step 2 Ch3-01~03 JSI · 동기 호출 · HostObject
Step 3 Ch3-05 메모리·생명주기 (JSI 객체 소유)
Step 4 Ch5-01~03 TurboModules와 Codegen
Step 5 Ch5-04 네이티브 모듈 직접 작성
Step 6 Ch5-05 경계 비용 — 무엇을 어디서 처리할지
Step 7 Ch7-02 흔한 병목과 회피 패턴
각 문서의 "📊 측정" 섹션에서 페이로드 크기·호출 빈도·지연을 확인하세요.
🟡 성능 병목을 찾고 고치는 개발자의 집중 코스
핵심 경로 (Old/New Architecture 양쪽에서 측정 가능해야 의미가 있음)
Step 1 Ch1-02 스레드 모델 — 누가 무엇을 하는지부터
Step 2 Ch2-03~05 Bridge의 한계 · 3스레드 흐름 · 왜 느린가
Step 3 Ch3-06 Bridge → JSI 비교 — 정량 차이의 출처
Step 4 Ch4-04 렌더 파이프라인 — 동기 측정이 가능해진 지점
Step 5 Ch6-02~03 Hermes 바이트코드 · V8과 비교 — 시작 비용의 정체
Step 6 Ch7-01 성능 측정 — Flipper · Systrace · perfetto · Instruments
Step 7 Ch7-02 흔한 병목 — 통신·리스트·이미지 디코딩
Step 8 Ch7-04 종합 실측 — 같은 화면을 Old/New로 매트릭스 비교
각 문서의 "💻 실전 실험"에서 도구를 직접 띄워 추적하세요.
모든 문서는 동일한 구조로 작성됩니다.
| 섹션 | 설명 |
|---|---|
| 🎯 핵심 질문 | 이 문서를 읽고 나면 답할 수 있는 질문 |
| 🔍 왜 이게 존재하는가 | 문제 상황과 설계 배경 |
| 😱 흔한 오해 또는 잘못된 사용 | Before — 많은 RN 개발자가 틀리는 방식 |
| ✨ 올바른 이해와 사용 | After — 경계를 알고 난 후의 올바른 접근 |
| 🔬 내부 동작 원리 | Bridge/JSI 호출 흐름 + Fabric 파이프라인 + Hermes 바이트코드 추적 |
| 💻 실전 실험 | 실행 가능한 RN 코드 + Flipper/DevTools 스크린샷 + 네이티브 모듈 작성 |
| 📊 측정 | Old vs New Architecture 비교 / Hermes vs JSC / 페이로드 크기별 호출 비용 |
| 🤔 트레이드오프 | 이 설계의 장단점, 언제 다른 방법을 택할 것인가 |
| 📌 핵심 정리 | 한 화면 요약 |
| 🤔 생각해볼 문제 | 개념을 더 깊이 이해하기 위한 질문 + 해설 |
Node + RN CLI + 시뮬레이터/실기. 핵심은 Flipper · React DevTools · Systrace · perfetto · Instruments · Chrome DevTools(Hermes CDP) · TurboModule 작성 입니다.
# 신규 프로젝트 (New Architecture · Hermes 기본)
npx react-native@latest init RNLab
cd RNLab
# 핵심 검증 도구 1 — Old/New Architecture 토글
# iOS: Podfile의 newArchEnabled 플래그
# Android: gradle.properties의 newArchEnabled=true
# → 같은 화면을 두 모드로 빌드해서 측정
# 핵심 검증 도구 2 — Flipper / React DevTools
# JS 스레드 프로파일, 네이티브 뷰 계층, 네트워크
# Fabric에서는 동기 측정·레이아웃 시각화
# 핵심 검증 도구 3 — 네이티브 스레드 추적
# Android: Systrace / perfetto trace
# python systrace.py -t 5 sched gfx view -a com.rnlab
# perfetto --txt -c trace.cfg -o trace.perfetto
# iOS: Instruments (Time Profiler · System Trace)
# → JS·Shadow·Main 스레드의 실제 분업을 타임라인으로 관찰
# 핵심 검증 도구 4 — Hermes 바이트코드 & 프로파일
hermesc -emit-binary -out app.hbc app.js
hermes-tool dump-bytecode app.hbc
# → 빌드 타임에 .hbc가 생성되는 흐름, 디스어셈블로 직접 확인
# Hermes sampling profiler 결과를 Chrome DevTools 형식으로 변환
npx hermes-profile-transformer input.cpuprofile -o chrome.cpuprofile
# Chrome → chrome://inspect → Hermes CDP로 직접 디버깅
# 실측 실험
# TurboModule(Codegen) Android(Kotlin) / iOS(Swift) 작성
# 큰 데이터(이미지 바이트·문자열)를 Bridge vs JSI로 N회 왕복 → 비용 비교
# 큰 리스트: FlatList vs FlashList — 메모리·스크롤 FPS 비교
# Yoga: 같은 Flexbox 트리가 웹/네이티브에서 동일하게 측정되는지 검증⬆️ 선행 학습
react-internals-deep-dive → Fiber와 재조정 (Fabric의 입력)
javascript-deep-dive → JS 의미와 이벤트 루프
android-framework-internals → android.View · Looper (네이티브 출력)
uikit-core-animation → UIView · Core Animation (네이티브 출력)
🤝 시너지
v8-engine-deep-dive → Hermes와 대비되는 V8 JIT 전략
event-loop-async-deep-dive → JS 스레드 · 마이크로태스크
flutter-deep-dive → "네이티브 뷰 제어" vs "자체 렌더" 대조
🧬 수렴 (렌더링 파이프라인 비교)
rendering-pipelines-compared → RN(네이티브 뷰) ↔ Flutter(자체 렌더) ↔ Web(브라우저)
공식 아키텍처
- React Native New Architecture — JSI · Fabric · TurboModules 공식 개요
- React Native Architecture Overview
- Hermes 공식 문서
- Yoga Layout
- "Inside React Native's New Architecture" — Meta Engineering 발표들
소스 코드
도구·실측
- Flipper — 네이티브 디버거 플랫폼 (Bridge/JSI 추적 플러그인)
- perfetto — Android 시스템 트레이싱 (Systrace 후속)
- hermes-profile-transformer — Hermes sampling profiler → Chrome DevTools 변환
- FlashList by Shopify —
FlatList병목을 해결한 고성능 리스트 (Ch7-02 사례)
⭐️ 도움이 되셨다면 Star를 눌러주세요!
Made with ❤️ by Dev Book Lab
"RN으로 만드는 것과, JS와 네이티브가 어떤 경계로 통신하는지 아는 것은 다르다"