Old Vs New ReactNative Architecture

권준혁·2024년 11월 20일
0

ReactNative

목록 보기
5/5

ReactNative의 구조를 알기 위해서는 기본적으로 New Architecture에 해당하지만, 이해를 돕기위해서 2021년 New Architecture가 나오기 전의 Old Architecture를 함께 알아보겠습니다.

Old Architecture 와 한계

Old Architecture는 Bridge based Architecture라고도 할 수 있습니다.

ReactNative는 크게 Native code와 Javascript Code 두 부분으로 나뉘어있으며, 두 다른 코드는 서로 소통하기위해 Bridge를 사용합니다. 바꿔말해 Birdge 없이는 두 부분은 소통할 수 없습니다.

UI가 그려지는 과정입니다.
먼저, 앱을 실행하면 OS에 의해 Main Thread(UI Thread)가 생성되고, Main Thread에 의해 Javascript Thread가 실행되며, Shadow Tree가 생성됩니다.
Shadow Tree는 Shadow Node로 구성되어 있으며, Shadow Node는 Javascript 영역에서 정의한 마운트될 Host Component를 나타냅니다. 그리고, Shadow Node는 React의 props와 레이아웃정보(x, y, width, height)를 포함하고 있습니다.

정적인 형태의 UI라면 여기서 끝이겠지만, 유저의 인터렉션에 의해 Native영역과 Javascript영역이 Bridge를 통해 어떻게 소통하는지 조금만 더 알아보겠습니다.

Bridge 동작방식

화면이 그려지고, Main Thread > Javascript Thread > Shadow Tree 순서로 모두 생성되었고, Button 컴포넌트가 그려졌고 버튼의 인터렉션 과정을 보겠습니다.

React 컴포넌트인 Button의 props또는 state가 변경되었다고 가정해보겠습니다. 변경된 상태값은 Javascript event loop iteration이 끝날 때마다 serialized JSON object 형태로 Bridge를 통해 Native영역에 전달되고, native view가 업데이트됩니다. (예를들면, 버튼이름이 변경되거나 Disabled되는 등)
반대로, 유저가 버튼을 클릭했을 때 이 Native Events도 브릿지를 통해 자바스크립트 영역으로 전달되며, 콜백이 실행됩니다.

Bridge Performance Bottleneck

이 과정은 Old Architecture에서 bottleneck 현상을 일으키기도해 성능이슈가 때때로 발생할 수 있으며, 유저 사용성면에서도 유저가 업데이트 이전의 중간상태값을 보게되는 등 문제가 있었습니다.
다시말해, 네이티브 영역에서 전달하는 NativeEvents와 Javascript & React 영역에서 전달하는 상태값이 불일치해 발생하는 이슈입니다. 이런문제들로 인해 구 버전의 React Native에서는 Javascript 영역에서의 과도한 애니메이션을 지양해야 했으며, 가능한 복잡한 애니메이션은 Main Threrad Native영역에서 구현하는 것이 좋았습니다.
일례로 리스트를 빠르게 스크롤할 때, 검은화면이 나타나게 되는 등의 문제를 겪기도 했었습니다.


New Architecture

New Architecture 는 Bridgeless 입니다.

Old Architecture의 여러 문제들을 해결하기위해 2018년부터 개발되어, 현재는 ReactNative 0.76 이상 에서 기본 설정으로 들어가있습니다. 강제하고 있지는 않기때문에 설정을 변경하면 0.76 에서도 Old Architecture를 사용할 수도 있습니다.

Glossary

New Architecture에 대해 알기위해서 몇 가지 중요한 용어들을 먼저 정리해보겠습니다.

Fabric

Fabric은 C++로 작성된 ReactNative의 새로운 렌더링 시스템입니다. iOS aOS같은 host platform들과 호환성을 확장하고, 성능면에서도 뛰어납니다.
레거시와 비교했을 때, 가장 큰 차이점이자 장점은 Bridge의 비동기 업데이트와는 다르게 동기적인 UI 업데이트가 가능해졌으며, React의 Concurrent Feature 나 serverside rendering을 사용할 수도 있어 UI가 일시적으로 깨지는 등의 좋지않은 유저경험을 방지하고, 렌더링 과정을 전보다 쉽게 개선할 수 있게 됐다는 점입니다.

JSI (Javascript Interface)

JSI는 Javascript code와 Javascript engine, Native 사이에 존재합니다.
이 JSI를 통해 Native와 Javascript 영역 간에 동기적인 소통이 가능합니다.
더 이상 Birdge를 통해 json을 serialize해 전달 할 필요가 없게됐으며 위에서 말한 Performance bottleneck 등의 이슈도 없어집니다.
또, Javascript Core 뿐 아니라 다양한 JS Engine들과 호환이 됩니다. (Hermes, v8 등)

Shadow Tree (New)

New Shadow Tree는 C++기반으로 작성되어 이 전과는 다르게 Native영역과 Javascript영역에서 공유됩니다. 이 전의 Shadow Tree는 모바일 런타임에서 Heap memory에 존재했던 것이 공유되기 때문에 메모리 점유면에서도 이점이 있고, Birdge를 통해 비동기방식으로 통신할 필요가 없어 성능이슈도 크게 줄었습니다.
이 Shadow Tree에서 Native Module에 대한 C++ 참조를 가질 수 있게 됐다는 점이 시사하는 바가 크다고 느껴집니다.

Turbomodule

전에는 Native Module을 작성하고 Javascript에서 사용하기 위해 Bridge를 사용했었습니다. New Architecture에서도 비슷한 작업을 해야하긴하지만, Codegen을 통해 ios, android 모두 C++ 모듈로 만들어집니다. 그래서 JSI를 통해 Javascript에서도 C++의 객체 레퍼런스를 가질 수 있어 호출할 수 있게됩니다.


요약

New Architecture가 각 부분들의 호환성과 성능에서 좋아졌고, Javascript와 Native가 동기적으로 참조가 가능하다는 점이 큰 의미가 있습니다. 앱을 운영, 유지보수 하다보면 자주 발생하던 네이티브 모듈을 참조할 수 없어 발생하는 JS layer에서의 앱 크래시 이슈도 배포 이전에 개발 단계에서부터 발견할 수 있어 현저히 줄어들게 될 것이고,
앱 시작시 불필요한 네이티브 모듈까지 로드할 필요가 없어 앱 시작시간도 빨라지게됩니다.
C++ 자체가 빠르기도 하지만, 필요한 네이티브 모듈을 필요한 때에 호출하게 되기 때문입니다.
(과거에는 모든 네이티브 모듈을 모두 initialize했어야 됐기 때문에 시작시간을 줄이기 위해서는 메뉴얼하게 하나씩 lazy load를 설정해야 했습니다.)
또, Javascript 영역에서 네이티브 모듈을 동기적으로 직접 참조할 수 있기 때문에, 성능면에서도 좋아져 기대가 됩니다.

하지만,
2024년 App.js Conf에서 발표한 성능개선에 대한 결과치입니다.
Android에서는 JNI 요구사항으로 인해 성능개선에 제한이 있었다고 합니다

발표자에 따르면, Framework 개발자라면 몰라도 앱 개발자입장에서 New Architecture도입을 꼭 해야하는 것은 아니라고 하니, 필요에따라 업그레이드하는 편이 좋아보이긴합니다.

지난 2-3년간 ReactNative에서 참 많은 변화가 있었습니다. 유지보수를 하면서 때때로 예상치 못한 이슈로 혼란스럽기도 했습니다.
New Architecture가 기본설정으로 정식릴리즈됨에 따라 곧 메이저 1버전도 릴리즈 될 수 있겠다는 기대도 생기네요.

주요 라이브러리들의 New Architecture 호환을 보려면 https://reactnative.directory/ 이 곳을 참고하면 되겠습니다
(https://github.com/reactwg/react-native-new-architecture/)

profile
웹 프론트엔드, RN앱 개발자입니다.

0개의 댓글