6 min read

React Native 내부 구조 이해하기: 이벤트, 스레드, UI

React Native 내부 구조 이해하기: 이벤트, 스레드, UI
Photo by Kelly Sikkema / Unsplash


React Native에서 발생하는 많은 문제는 API 사용법의 문제가 아니라, 데이터와 제어 흐름이 어떤 스레드를 거쳐 어떤 형태로 UI에 도달하는지를 명확히 이해하지 못한 데서 비롯됩니다. UI가 멈춘 것처럼 보이거나, 터치 반응이 늦고, 애니메이션과 상태 업데이트의 타이밍이 어긋나는 현상은 모두 JS Thread와 UI Thread가 분리된 구조 위에서 동작하기 때문에 발생합니다.

과거의 Bridge 아키텍처는 “JavaScript만으로 네이티브 앱을 만든다”는 목표 아래 JS와 Native를 명확히 분리하고, JSON 기반의 비동기 메시지로 연결하는 안정적인 구조를 선택했습니다. 하지만 이 설계는 직렬화 비용, 항상 비동기라는 제약, 그리고 JS Thread 상태가 UI 반응성에 영향을 주는 한계를 함께 가져왔습니다.

New Architecture는 단순한 성능 개선이 아니라, JS와 Native 사이의 경계를 줄이고 불필요한 데이터 변환 단계를 제거하기 위한 구조적 재설계입니다. JSI를 통해 메모리를 참조하고, UI Thread가 JS를 덜 의존해 동작할 수 있게 되면서 “JS가 멈춰도 UI는 멈추지 않는” 실행 모델이 가능해졌습니다.

이 글에서는 이벤트가 발생하는 순간부터 실제 UI가 그려질 때까지 어떤 스레드와 큐를 거치는지를 따라갑니다.


React Native에는 어떤 스레드들이 존재할까요?

React Native 애플리케이션은 기본적으로 여러 개의 스레드 위에서 동작합니다.

1. Main Thread (UI Thread)

  • 네이티브 UI를 실제로 그리는 스레드입니다.
  • OS의 이벤트 루프를 따르는 싱글 스레드입니다.
  • View 생성, 레이아웃, 제스처 처리, 애니메이션 실행이 이곳에서 이루어집니다.

2. JS Thread

  • JavaScript 로직이 실행되는 스레드입니다.
  • 역시 싱글 스레드 + 이벤트 루프 구조입니다.
  • React의 렌더 계산, 상태 업데이트, 비즈니스 로직이 여기서 처리됩니다.

3. Native Module Threads

  • 네이티브 모듈이 내부적으로 사용하는 보조 스레드들입니다.
  • 네트워크, 디스크 IO, 연산 작업 등을 처리합니다.

React는 직접 화면을 그리지 않습니다

여기서 가장 중요한 오해를 먼저 정리하겠습니다.

  • React가 하는 일은 다음과 같습니다:
    • “이 위치에 View가 필요합니다”
    • “여기에 Text 노드가 있어야 합니다”
  • 즉, UI의 트리를 계산합니다

이 과정은 이렇게 진행됩니다

  1. JS Thread
    • React가 Virtual Tree를 계산합니다
    • 변경 사항(diff)을 산출합니다
  2. 이 설계 정보가
    • (구 아키텍처에서는 Bridge를 통해)
    • (뉴 아키텍처에서는 Fabric/JSI를 통해)
  3. UI Thread로 전달됩니다
  4. 실제 그리기는 UI Thread가 수행합니다

React는 “무엇을 그릴지”를 결정하고, UI Thread는 “실제로 그리는 책임”을 집니다.

이벤트 리스너는 어떻게 동작할까요? (Bridge 기반)

기존 Bridge 기반 React Native에서 이벤트 흐름은 다음과 같습니다.

UI Thread (OS Event Loop)
 └─ 터치 발생
     ↓
Native Event System
     ↓ (JSON 메시지 생성)
Bridge
     ↓ (비동기 Task Queue)
JS Thread (JS Event Loop)
 └─ 이벤트 핸들러 실행
  • 이벤트는 항상 비동기적으로 JS Thread에 전달됩니다
  • 이 과정에서
    • JSON 직렬화가 발생하고
    • 메시지 큐를 통과하며
    • JS 이벤트 루프의 Task Queue에 적재됩니다

따라서 JS Thread에서 콜스택을 오래 점유하는 무거운 연산이 수행되면, JS Event Loop 특성상 이벤트 처리 지연, UI 반응 저하(체감상 UI 블로킹)가 발생합니다

Native UI Thread 자체는 멈추지 않지만, JS의 응답이 늦어 UI가 멈춘 것처럼 보이는 현상이 나타나는 구조입니다.


뉴 아키텍처에서는 무엇이 바뀌었을까요?

JSI는 자바스크립트가 C++ 객체에 대한 참조를 유지하고, 반대로 C++ 객체도 자바스크립트 객체에 대한 참조를 유지할 수 있도록 하는 인터페이스입니다. JSI 덕분에 직렬화 할 필요가 없어지게 됩니다.

JS Thread
  ↕ JSI
C++ Native Binding
  ↕ TurboModules
Native Thread / UI Thread
  • 이로 인해 동기 호출이 가능해지고,
  • 이로 인해 Promise / 콜백이 필수가 아니게 됩니다.

내용이 더 궁금하시면 이 글을 참조 해주세요.


UI Thread 로직의 독립 실행

뉴 아키텍처에서는 다음 로직들이 UI Thread에서 직접 실행될 수 있습니다. JS Thread에 대한 의존성이 줄어들게 됩니다.

  • 제스처 처리
  • 애니메이션 계산
  • 스크롤 반응
  • transform 적용

그 결과 JS Thread가 멈추더라도 UI Thread는 정상적으로 동작합니다. 즉, 애니메이션, 제스처, 스크롤 같은 UI Thread에서 다룰수 있는 로직들은 부드럽게 유지할수가 있게 되었습니다.


마무리

뉴 아키텍처의 핵심은 “더 빠르다”라는 면도 있지만, 코드를 작성함에 있어서 "이 코드는 JS Thread에서 실행되어야 한다." 혹은 "UI Thread에서 실행되어야 한다." 를 판단할수 있게 된것입니다.

아마 다음으로 이어질 질문들은

  • 언제 JS Thread에서 처리해야 할까요?
  • 언제 UI Thread에서 처리해야 할까요?
  • 이 선택권이 아키텍처 설계 난이도에 어떤 영향을 줄까요?

이런 것들이 아닐까 싶습니다.


참고

About the New Architecture · React Native
Since 2018, the React Native team has been redesigning the core internals of React Native to enable developers to create higher-quality experiences. As of 2024, this version of React Native has been proven at scale and powers production apps by Meta.

https://medium.com/%40antoniogally/exploring-react-natives-architectures-bridge-and-beyond-76e414accf7d

https://medium.com/%40jalalmohammed1818/react-native-new-architecture-fabric-old-vs-new-a-visual-deep-dive-d8436c103457