React Native Deep Dive

React Native Deep Dive


React Native 아키텍처를 이해하기

React Native 아키텍처를 깊이 이해하는 건 개발자가 성능을 최적화하고, 효율적으로 디버깅하며, 최신 기술을 활용해 고품질의 확장 가능한 애플리케이션을 구축하는 데 중요함.

구 아키텍처: Bridge 모델

구 아키텍처에서는 React Native가 두 개의 별도 세상에서 작동했음:

  • JavaScript World — 앱 로직이 실행되는 곳
  • Native World — UI와 시스템 기능이 작동하는 곳

이 두 세상은 서로 다른 언어(JavaScript vs Swift/Java/Kotlin)를 사용하므로 통신 방법이 필요했음. 바로 여기서 Bridge가 등장함.

Bridge가 어떻게 작동하는가?

  • JavaScript 측은 JSON 메시지를 통해 Native 측에 무엇을 해야 할지 알려줌.
  • Native 측은 이 메시지를 읽고 UI를 렌더링하거나 텍스트를 업데이트하는 등의 작업을 실행함.
  • 사용자가 UI와 상호작용하면(예: 버튼 클릭 시) Native 측은 다시 JavaScript로 메시지를 보냄.

예시: 로그인 화면 만들기

  1. JavaScript는 Bridge를 통해 메시지를 보냄:
    • "이 스타일로 입력 필드를 만들어라"
    • "이 속성으로 버튼을 만들어라"
  2. Native 측은 메시지를 받고 UI를 렌더링함.
  3. 사용자가 텍스트를 입력하면 Native 측은 데이터를 JavaScript로 다시 보냄.

React Native의 Thread(구 아키텍처)

React Native 앱은 여러 Thread에서 실행됨:

  • JavaScript Thread — 모든 React Native 논리를 실행하고 UI 업데이트를 처리함.
  • Native Thread — UI 요소에 대한 플랫폼 특정 코드(Swift, Java/Kotlin)를 실행함.
  • 쉐도우 Thread — 레이아웃을 처리하는 Yoga Engine을 사용해 스타일을 Native 레이아웃으로 변환함.

구 아키텍처의 단점

🚨 1. 성능 문제

  • JavaScript와 Native 간의 통신이 느려서 메시지가 비동기적으로 전달됨.
  • UI 업데이트가 늦어지면 스크롤에 지연이 발생할 수 있음.

🚨 2. 메모리 공유 불가

  • JavaScript와 Native는 메모리를 공유하지 않음.
  • 대신 데이터를 JSON 형식으로 복사해 전달하는데, 이로 인해 성능이 저하됨.

🚨 3. Native Module 로딩의 비효율성

  • React Native는 필요하지 않은 Native Module도 앱 시작 시 모두 로드함. 이로 인해 로드 시간이 길어짐.

🚨 4. 기여가 어려움

  • React Native의 코드베이스가 복잡해서 개발자들이 개선하거나 수정하는 게 어려움.

새로운 아키텍처: Fabric과 Turbo Modules

이 문제를 해결하기 위해 React Native는 새로운 아키텍처인 FabricTurbo Modules를 도입함.

Fabric이란 무엇인가?

Fabric은 Bridge를 제거하고 JavaScript와 Native 간의 더 빠르고 효율적인 통신 모델을 제공함.

Fabric이 더 좋은 이유?

  • 비동기 메시지가 아닌 동기식 통신을 사용함.
  • JavaScript와 Native가 메모리를 공유해 데이터 복사 필요성을 줄임.
  • UI 응답성과 부드러움을 개선함.

Turbo Modules란 무엇인가?

Turbo Modules는 React Native가 시작 시 모든 Native Module을 로드하는 대신, 필요한 Module만 로드할 수 있게 함.

Turbo Modules가 더 좋은 이유?

  • 앱 시작 시간을 줄임.
  • 필요할 때만 Module을 로드해 메모리를 절약함.

비교: 구 아키텍처 vs 새로운 아키텍처

React Native 앱 아이콘을 클릭했을 때의 흐름

  1. 1단계: 앱 시작 & UI 관리자 시작
    앱 아이콘을 클릭하면 운영 체제가 앱을 실행하고 React Native를 시작함. UI 관리자는 텍스트 필드, 버튼, 이미지 등의 Native 컴포넌트를 초기화함.

  2. 2단계: JavaScript 번들 로드
    React Native는 MainBundle.js를 로드해 앱의 모든 JavaScript 코드를 포함함.

  3. 3단계: Bridge를 통한 뷰 생성 (구 아키텍처) 또는 Fabric (새로운 아키텍처)

    • 구 아키텍처: JavaScript는 Bridge를 통해 JSON 메시지를 보내 UI 요소를 생성함.
    • 새로운 아키텍처: Fabric은 Native 코드와 직접 상호작용해 UI 렌더링을 더 빠르게 만듬.
  4. 4단계: 레이아웃 계산 (Yoga Engine 사용)
    React Native는 웹에서 사용하는 표준 CSS 대신 Yoga Engine을 사용해 레이아웃을 계산하고 요소의 위치를 설정함. 쉐도우 Thread가 이 레이아웃 처리를 담당함.

  5. 5단계: UI가 화면에 표시됨
    마지막으로 UI 관리자는 계산된 레이아웃을 기반으로 UI를 표시함. 앱이 완전히 로드되고 사용할 준비가 됨! 🎉

앱 시작 시의 흐름

  1. UI 관리자는 Native 컴포넌트를 초기화함.
  2. JavaScript는 MainBundle.js를 로드함.
  3. Yoga Engine을 사용해 레이아웃을 계산함.
  4. UI가 화면에 표시됨.

MainBundle.js에 무엇이 포함되어 있는가?

MainBundle.js(또는 Android의 index.bundle)는 React Native 애플리케이션에서 모든 JavaScript 코드를 포함하는 번들임. 이 파일은 앱 빌드 시 생성됨.

MainBundle.js에 포함되는 것들:

  • 모든 JavaScript 코드 — React Native 애플리케이션의 전체 논리.
  • React 및 React Native Core API — 렌더링을 위한 필수 라이브러리.
  • Metro Bundler 변환 — 최적화되고 축소된 JavaScript 코드.
  • 서드파티 라이브러리 — Axios, Redux 등 외부 라이브러리.
  • Native Bridge 호출 (구 아키텍처 사용 시) — Native 컴포넌트와의 통신 코드.

MainBundle.js는 어떻게 생성되는가?

React Native의 Metro Bundler는 모든 JavaScript 파일을 컴파일해 MainBundle.js라는 단일 파일로 번들링함.

Metro Bundler의 역할

  • ES6+ JavaScript를 ES5 문법으로 변환함.
  • 여러 JavaScript 파일을 하나의 번들로 결합함.
  • 코드를 최적화해 프로덕션을 위한 축소(minify) 작업을 함.
  • 개발 중 핫 리로딩을 처리함.

간단한 비유

React Native 앱을 음식점에서 음식을 주문하는 것으로 비유할 수 있음:

  • ☕ JavaScript Thread (고객) - 어떤 종류의 커피를 주문할지 결정함(앱 논리).
  • 🧑‍🍳 Bridge (바리스타) - 주문을 전달받고 커피를 만드는 과정으로 넘김.
  • 🍵 Native 측 (커피 머신) - 커피를 만들고 필요한 추가 작업을 처리함(UI 렌더링).
  • 🛎 UI 관리자 (서빙 직원) - 완성된 커피를 고객에게 전달함(UI를 표시).

음식점이 너무 바쁘면(Bridge 요청이 많으면) 서비스가 느려짐. 그래서 React Native의 최신 버전에서는 성능 향상을 위해 Bridge 의존도를 줄였음.

주요 요약 (구 아키텍처)

  • React Native는 모바일 앱을 JavaScript로 작성할 수 있게 해주지만 여전히 Native 컴포넌트를 사용함.
  • JavaScript와 Native 측을 연결하는 Bridge가 커피 주문과 전달을 처리하는 역할을 함. UI 업데이트는 비동기적으로 이루어져 지연이 발생할 수 있음. Shadow Thread가 스타일을 모바일 OS가 이해할 수 있는 형식으로 변환함.
  • 구 아키텍처는 Bridge 사용으로 인해 성능 저하가 발생하고, 이를 해결하기 위해 Fabric과 Turbo Modules와 같은 개선 사항이 도입됨.

간단한 비유 (새로운 아키텍처)

새로운 시스템에서는 모든 것이 더 직관적이고 효율적임. React Native 앱은 다음과 같음:

  • ☕ JavaScript Thread (고객) - 고객이 원하는 커피를 빠르게 결정함(앱 논리).
  • 🧑‍🍳 Fabric (바리스타) - 커피를 직접 만들고, 필요한 모든 작업을 한 번에 처리함(UI 렌더링).
  • ⚙️ Turbo Modules (고급 커피 도구) - 특수한 커피 머신으로 특별한 요구를 처리함(카메라나 GPS와 - 같은 Native 기능 접근).
  • 🛎 직접 통신 (서빙 직원) - 커피가 준비되면 바로 고객에게 전달함, 지연 없이 빠르게!

새로운 시스템에서는 커피가 더 빠르고 직관적으로 제공되며, 이전보다 더 효율적이고 즉각적인 서비스를 경험할 수 있음.