본문 바로가기
FE Development/React-Native

React Native 작동방식

by 개발자 데이빗 2021. 10. 7.

이해를 돕는 용어

RootView?

네이티브 화면들이 구성되는 컨테이너 역할 ( 자바스크립트 컴포넌트의 네이티브 표현방식 )

브릿지?

RootView를 포함한 대부분의 네이티브 쪽은 특정 플랫폼에 맞는 언어(Object-C 혹은 Java)로 작성되어 있다.

하지만 브릿지는 전부 C++로 작성되어 있다.

브릿지 인터페이스는 전자와 후자를 상호작용하도록 도와준다.

브릿지는 자바스크립트 -> 네이티브, 네이티브 -> 자바스크립트 두개의 엔드포인트를 가진다.

 

UIManagerModule?

모든 자바스크립트 UI 컴포넌트와 이와 연관된 네이티브 화면 간의 맵핑 정보를 저장하고 있다.

자바스크립트 컴포넌트가 생성되거나 업데이트되거나 삭제될 때마다 이 맵핑 정보를 이용해 적절하게 관련 네이티브 뷰를 생성하거나 업데이트하거나 삭제한다.

또한 화면상에 보여주기 위해 변경사항을 RootView에 저장된 Native 뷰 트리에 전달한다.

 

Native Modules

각 플랫폼에 대해 기본적으로 구현되는 자바스크립트 함수 집합이다.

네이티브 기능이 필요하거나 리액트 네이티브에 해당 모듈이 아직 없는 경우 또는 네이티브 성능이 더 좋은 경우에 사용된다.

React Native 어플리케이션에서 호출할 함수만 만들 수 있다.

 

BatchedBridge

잡자스크립트에서 네이티브로의 호출을 저장하는 역할을 한다.

호출이란 네이티브 모듈 id, 메서드 id 그리고 인자를 포함한 객체이다.

주기적으로 global.flushQueue()를 호출하며 이때 컨텐츠를 자바스크립트에서 C++ 브릿지의 네이티브 쪽으로 전달한다.

 

스레드 

1. UI 스레드

메인 스레드, 기본 안드로이드 또는 IOS UI 렌더링에 사용된다.

2. JS 스레드

대부분의 경우 리액트 네이티브 앱은 비즈니스 로직을 자바스크립트의 스레드 레벨에서 처리한다.

네이티브 기기와 통신하는 모든 자바스크립트의 기능은 분리된 별도의 스레드로 처리된다.

모든 스크립트의 동작은 네이티브 플랫폼과의 인터랙션에서 별도의 스레드로 처리된다.

이로 인해 UI와 Animation의 구동이 별도의 간섭없이 자연스럽게 보이게 된다.

React Native 앱 내에서 실행되는 스레드는 API 호출과 터치 이벤트, 인터랙션을 처리한다.

네이티브 뷰에 대한 변화는 일괄 처리되어 JS 스레드의 각 이벤트 루프 끝에서 네이티브 쪽으로 전달되며 마지막에 UI 스레드에서 실행된다.

3. Native Modules 스레드 ( 자바스크립트에서 네이티브 기능 사용 )

각 플랫폼에 대해 기본적으로 구현되는 자바스크립트 함수 집합이다.

네이티브 기능이 필요하거나 리액트 네이티브에 해당 모듈이 아직 없는 경우 또는 네이티브 성능이 더 좋은 경우에 사용된다.

React Native 어플리케이션에서 호출할 함수만 만들 수 있다.

4. Render 스레드

Android L 에서만 React Native 렌더링 스레드가 UI르 그리는데 사용되는 실제 OpenGL 명령 생성에 사용된다.

 

리액트 네이티브 앱을 시작하면 일어나는 일

처음 앱을 실행하면 가지게 되는 것

- 애플리케이션 코드

- 휴대폰의 운영체제에 의해 할당 받는 유니크한 스레드인 메인 스레드

리액트 네이티브의 코드 (스레드)

프레임워크 코드 : 매번 작성하지 않아도 되는 코드

커스텀 코드 : 앱을 실제로 묘사하는 코드

그리고 각각의 Native 코드와 자바스크립트 코드

 

메인 스레드는 프레임워크 코드의 네이티브 코드 부분이며 UI 스레드라고도 불린다.

UI 코드는 자바스크립트로 작성되지만 결국 네이티브 뷰로 렌더링 된다.

이 과정에서

1. 네이티브 뷰를 만들고 자바스크립트 컴포넌트와 연결 (UIManagerModule에 의해서 처리됨)

2. 위에서 만든 네이티브 뷰를 저장하고 화면에 표시 (첫번째 과정이 이뤄지는 동안 RootView에 의해 처리됨)

 

모든 것은 브리지 인터페이스로 이동하기 전에 RootView에서 시작한다.

브릿지는 dispatch 호출을 할 수 있는 엔드포인트가 없다면 아무 의미가 없다.

이러한 엔드포인트가 Native Modules 이다.

 

각 모듈은 인스턴스를 만들고 인스턴스에 대한 레퍼런스가 자바스크립트 -> 네이티브 브릿지에 저장된다.

그래서 나중에 자바스크립트로부터 호출 될 수 있다.

브릿지 인터페이스에 대한 참조가 각 Native Module에 전달될 수 있는데 이를 통해 직접 자바스크립트를 호출할 수 있다.

 

마지막으로 두개의 추가적인 스레드 JS 스레드와 NativeModules 스레드가 생성된다.

 

자바 스크립트 실행

자바 스크립트 엔진

스크립트 언어인 자바스크립트는 바이트 코드로 변환한 후에 수행되어야 한다.

이는 자바스크립트 엔진을 통해 이루어진다.

debug 모드에서 자바스크립트 코드는 V8 엔진을 사용하고 브라우저에서 직접 실행된다.

디바이스에서는 자바스크립트 코어를 기본으로 사용한다.

자바스크립트코어는 IOS에는 기본적으로 포함되어 있지만 안드로이드에는 포함되어 있지 않다.

그래서 리액트 네이티브는 안드로이드 앱에서 이 복사본을 자동으로 번들링한다.

때문에 IOS에 비해 안드로이드 앱이 좀 더 무겁다.

 

글로벌 객체

자바스크립트 엔진을 효과적으로 실행하기 위해 React Native는 실행 환경에 대한 컨텍스트를 제공해야 한다.

글로벌 객체는 C++ 브릿지에 생성되고 저장되며 자바스크립트 환경 뿐만 아니라 외부에서도 접근 가능하다.

글로벌 객체는 네이티브와 자바스크립트 사이에서 기본적인 통신 수단이며,

일부 기본적인 기능( 자바스크립트에서 네이티브로 데이터를 전달하는데 사용되는 기능 )을 제공한다.

ModuleConfig 배열의 각 항목은 Native Module에 대한 정보를 기술한다. (이름, 외부로 노출되는 상수, 함수 등을 포함한다.)

flushQueue() 함수는 자바스크립트와 네이티브 환경 사이의 통신을 보장하게 해주는 역할을 한다.

자바스크립트 컨텍스트가 완전이 생성되면 자바스크립트 엔진으로 보내진다.

그리고 JS 스레드에서 React Native 자바스크립트 번들을 로딩하기 시작한다.

 

자바스크립트 번들 로딩

자바스크립트 엔진이 프레임워크의 자바스크립트 부분을 처리하기 시작할 떄 BatchedBridge를 생성한다.

다음은 NativeModules 객체를 만든다. NativeModules는 ModuleConfig 배열을 이용하여 채워진다.

코어 자바스크립트 모듈을 만들고 JS 스레드에서 자바스크립트 번들을 로딩한다.

코어 자바스크립트는 이벤트를 네이티브에서 자바스크립트로 보내주는데 사용되는 DeviceEventEmitter와 앱의 메인 컴포넌트에 대한 참조 정보를 저장하는 AppRegistry를 포함하고 있다.

네이티브에서 호출 가능하게 하기 위해 이 모듈들은 자바스크립트 글로벌 객체에 등록 되어야 한다.

앱 화면 상에 표시

자바스크립트 번들을 로딩하는 것은 JS 스레드에서 일어나는데 이는 메인(UI)스레드와는 독립적이다.

JS 스레드는 자신의 일이 끝났음을 메인스레드에 알려주고 메인스레드는 AppRegistry를 사용해서 JS 스레드가 메인 커스텀 컴포넌트(App.js)를 처리하도록 요청한다.

UI 컴포넌트를 만날 때마다 UIManagerModule을 호출하게 되며 UIManagerModule은 네이티브 뷰를 만들고 이를 RootView에 저장한다.

댓글