React 아니고 React Native요! (React Native 지원)

React와 React Native의 공통점과 차이점을 정리하고, 나아가 React Native에서 왜 성능 모니터링이 필요한지도 함께 알아보았습니다.

작성일 2023년 05월 15일

안녕하세요, IMQA의 노성현입니다.
지난주 IMQA에서는 React Native를 모니터링 하는 서비스를 공개하였는데요.

React는 기존 IMQA의 web agent를 통해 모니터링이 가능했지만, React Native는 IMQA의 WebAgent를 이용하여 모니터링 할 수 없었어요.

이번 포스팅을 통해 IMQA에서는 React Native를 지원하기 위해 어떤 것들을 고민했고, 어떻게 만들었는지 소개해 보려고 해요.

React 아니고 React Native요!

IMQA에서는 다양한 플랫폼을 지원하고 있어요. 기본적으로 네이티브 형태의 앱과 하이브리드 형태의 웹뷰 기반 앱을 모니터링할 수 있어요.

이 중 하이브리드 형태의 경우 SSR 형태의 웹페이지도 있었지만, 최근에는 Vue, React와 같은 프레임워크 기반의 웹 서비스를 웹뷰로 제공하는 하이브리드 형태의 앱을 모니터링 하고 싶어 하시는 고객분들의 요구사항이 많았죠.

그래서 IMQA에서는 다양한 형태의 웹 사이트를 모니터링 하기 위해 Event Injecting 기반의 기존 webview에서 PerfomanceObserver 기반의 웹 표준 방식으로 모니터링 방법을 바꿨습니다.

하지만..

요구사항을 잘못 전달 해준 영업사원 정품질! React와 React Native의 차이를 몰랐던 우리의 영업사원 정품질은 요구 사항을 잘못 전달 전달해 주었는데요.

이 과정에서 정품질뿐만 아니라 생각보다 많은 분께서 React와 React Native가 같은 거라고 잘못 알고 계시거나, 다른 거라는 것을 알아도 차이점에 대해선 제대로 모르신다는 걸 알게 되었는데요.

그렇다면 React와 React Native의 공통점과 차이점은 무엇일까요?

React와 React Native의 공통점과 차이점은 무엇일까요?

우선 기본적인 공통점으로는 JavaScript라는 언어를 사용한다는 점입니다. (Typescript도 지원하죠.)

또한 비슷한 문법과 구조를 가집니다. 컴포넌트 기반으로 개발하는 점, JSX 문법을 사용하는 점에 있어 매우 비슷합니다. 아주 정확히는 React의 방식으로 네이티브 앱을 만들기 위해 React Native가 등장했기 때문에 둘은 개발 형태가 같을 수밖에 없었죠.
그렇기에 useEffect, useRef와 같은 Hook들의 사용법도 거의 비슷합니다. 또한 둘 다 Virtual DOM을 쓰기 때문에, 어플리케이션의 성능이 좋습니다.

하지만 이것 이외에는 실제 동작하는 내용은 완전히 다릅니다.

React React Native
UI 렌더링 브라우저 iOS, AOS
DOM 조작 필요 필요하지 않음
CSS 스타일링 CSS, Sass 등 Flexbox, StyleShe
모바일 하드웨어 접근 불가능 가능
라이브러리 React DOM, React Router 등 React Native, Expo 등

1. UI 렌더링

React는 웹이기 때문에 브라우저에서 동작하는 반면, React Native는 iOS와 AOS 같은 모바일 환경에 맞춰 동작합니다. 이 말이 좀 어려운 것이 React로 하이브리드 앱을 만들 수 있는데 React와 React Native로 앱을 만드는 게 정확히 무슨 차이인지 헷갈리시는 분들도 많은데요.

React로 앱을 만드는 경우는 React로 만든 웹사이트를 Webview로 띄우는 방법으로 앱을 만들게 됩니다. React Native로 앱을 만드는 경우에는 React Native가 네이티브 코드가 되는 것입니다. 실제 React Native가 네이티브 코드가 되는 부분은 더 자세히 다루겠습니다.

2. DOM 조작

React는 DOM을 조작하는 방식으로 UI를 업데이트하는 반면, React Native는 DOM 조작을 하지 않고, Javascript와 네이티브 모듈을 사용하여 네이티브 UI 구성 요소를 조작합니다. 이때 React Native는 DOM을 조작하지 않는다면 Virtual DOM은 필요 없는 거 아닐까요?

React Native는 네이티브 UI 구성 요소를 사용하여 UI를 렌더링하는데요. 이때 이러한 네이티브 UI 구성 요소는 React Native의 Virtual DOM에서 사용되는 것과는 다른 방식으로 동작합니다.

Virtual DOM은 변화된 부분만 렌더링할 수 있는 장점이 있는데요. React는 html을 Virtual DOM으로 처리하고, React Native는 네이티브의 UI를 Virtual DOM으로 관리하게 됩니다.

그래서 React Native에 화면이 바뀌는 경우 Virtual DOM을 이용하기 때문에 변경된 부분만 다시 렌더링하게 되어 결과적으로 좋은 성능을 만들어 낼 수 있는 것이죠.

3. CSS 스타일링

React Native는 웹은 아니기 때문에 CSS 스타일을 사용하지 않습니다. 대신 Flexbox나 StyleSheet를 사용하죠.

이때 CSS뿐만 아니라 웹에서 사용하는 컴포넌트도 사용하지 않습니다. 예컨대 div나 input과 같은 웹 컴포넌트 대신 View와 Text 같은 Native UI 컴포넌트를 사용합니다.

4. 모바일 하드웨어 접근

React Native는 네이티브이기 때문에 디바이스에 있는 다양한 하드웨어에 API만 있다면 모두 제공받을 수 있습니다.

React에서도 GeoLocation을 이용하여 디바이스 위치를 가져오기도 합니다만, 이러한 웹 표준 기술 이외에 네이티브에 Sqlite로 데이터를 저장하거나, 네이티브로 이미지를 캐싱하거나 하는 다양한 네이티브 모듈을 사용할 수 있게 되는 거죠. 물론 React도 webview에서 Bridge를 통해 통신을 못 하는 건 아닙니다.

5. 라이브러리

사용하는 라이브러리에서도 많은 차이가 납니다. React는 주로 React DOM과 React Router, Redux와 같은 라이브러리를 사용하지만, React Native는 React Native, Expo, React Navigation을 사용하죠.

위에 그림에서 보았듯 React Component는 같더라도 실제 동작은 다르죠. 특히 React Native의 동작을 보면 네이티브(iOS, AOS)와 React Native 사이에 Bridge가 있는 것을 알 수 있는데요.

이때 Bridge라는 것이 webview와 native 간에 서로 통신하기 위해 사용하던 용어이기 때문에 React Native가 웹뷰에서 동작한다고 이해하고 계신 분들도 있으실 텐데요.

실제 React Native가 동작하는 런타임을 보면 iOS는 Safari에서 구동하는 JavaScript Engine인 JavaScriptCore를 사용하고, AOS는 V8을 엔진으로 사용합니다. 물론 웹뷰도 해당 엔진을 사용하겠지만 동작하는 런타임이 다르다는 점이 기존 React를 이용한 웹뷰 기반 앱과 React Native 앱의 차이점입니다. React Native는 Javascript Engine만 사용하죠.

또한 iOS에서 사용되는 JavaScriptCore는 iOS에 쓰기 가능한 실행 가능 메모리가 없어 JIT(Just-In-Time)컴파일러를 사용하지 않습니다. 대신 AOT(Ahead-of-Time)을 사용하죠. AOT 컴파일러는 미리 컴파일된 코드를 실행하는 방식으로 작동합니다. 이렇게 하면 JavaScript 코드를 실행하는데 드는 시간이 줄어들고, 앱의 성능이 향상됩니다.

반대로 AOS의 경우 V8을 사용하기 때문에 JIT 컴파일러를 사용합니다. 이러한 경우 iOS에서 사용하는 JavaScriptCore보다 일반적으로 빠르고 성능이 좋습니다. 또 많은 분들이 아시다시피 웹 브라우저에서 V8을 많이 사용하고 있기 때문에 성능에 있어 많은 경험이 쌓인 엔진이라고 볼 수 있습니다.

이렇게 엔진에 차이가 있어 같은 코드를 동작시키더라도 다른 성능을 발생시킬 수 있기 때문에 iOS와 AOS의 성능 테스트를 하거나 모니터링할 때 각각 분리하여 모니터링 하셔야 합니다.

위의 설명과 같이 React Native은 웹뷰를 사용하지 않기 때문에 웹표준으로 개발된 IMQA WebAgent는 React Native에서 동작하지 않았습니다.

그렇기 때문에 IMQA팀은 React Native용 Agent를 새롭게 개발하여 제공하기로 했습니다.

IMQA가 지원하는 React Native는 무엇이 달라졌나요?

iOS의 View Controller나 AOS의 Activity와 같이 IMQA는 화면의 단위로 성능 지표를 제공해 드렸는데요.

하지만 React Native의 화면 단위는 무엇일까요? 바로 컴포넌트입니다! React Native는 모두 컴포넌트 단위로 화면을 구성합니다. 아래 이미지를 통해 살펴볼까요?

이미지에서 표시된 빨간색 영역도 컴포넌트, 노란색 영역도 컴포넌트죠. IMQA 팀은 어떤 기준으로 화면 단위를 구성해야 하는지 고민했습니다.

고민 끝에 ReactAgent에서 컴포넌트 렌더링을 수집하는 타입을 Root가 되는 부모 컴포넌트, 자식 컴포넌트를 수집하는 API를 제공하게 되었어요.

  • ../components/MyComponent.tsx (부모 컴포넌트)
// RNMpmAgentModule import 
import MpmAgent from ‘imqa-react-native-module’; 

..

const MyComponent = () => {

.. 
useLayoutEffect(() => { 
 // 해당 설정은 화면의 rendering이 이루어 지기전에 호출되어야 하는 함수이므로 
 // 꼭 useLayoutEffect Hook 에서 적용 부탁 드립니다. 
 MpmAgent?.setBehaviorData("MyComponent"); 
}, []);

useEffect(() => {
 // useEffect 함수의 최상단에 위치해야 합니다. 
 MpmAgent?.startReactNativeRender("MyComponent",true); 
 ..

 // useEffect 함수의 최하단에 위치해야 합니다. 
 MpmAgent?.endReactNativeRender("MyComponent",true);
}, []);
..
}
  • ../components/MyChildComponent.tsx (자식  컴포넌트)
// RNMpmAgentModule import
import MpmAgent from ‘imqa-react-native-module’; 

..
const MyChildComponent = () =>

useEffect(() => {
 // useEffect 함수의 최상단에 위치해야 합니다. 
 MpmAgent?.startReactNativeRender("MyChildComponent", false); 
 ..

 // useEffect 함수의 최하단에 위치해야 합니다. 
 MpmAgent?.endReactNativeRender("MyChildComponent", false);
}, []);

이런 식으로 컴포넌트라는 개념이 IMQA에 새롭게 추가되었습니다.

여러분들이 체크하고 싶은 컴포넌트에 IMQA 코드를 삽입하시면 실제 사용자의 성능 데이터를 모니터링 하실 수 있습니다.

React Native 앱을 운영하고 있는데 꼭 모니터링 해야 할까요?

React Native는 개발자가 가장 많이 사용하고 있는 프레임워크 중 하나입니다. 오죽하면 최신 메이저 버전이 아직 1도 안 찍혔는데도 엄청나게 인기가 있죠. 많은 장점이 있는 프레임워크지만, 은탄환은 없듯이 단점도 분명히 존재합니다.

1. 3rd Party 라이브러리를 많이 사용하시진 않으셨나요?

여러분들의 앱은 순수하게 React Native로만 만드셨나요? 혹시 다양한 3rd Party 라이브러리를 많이 사용하셨거나, 네이티브 화면들도 제공하고 계시진 않으신가요?

저 같은 경우에도 React Native의 장점 중 하나인 다양한 UI 컴포넌트 오픈소스들을 이용해서 개발하는 경우가 많은데요. 개발 생산성을 위해 많은 3rd Party 라이브러리를 사용하신 경우, 안정성을 위한 모니터링은 어느 정도 필수라고 말씀드릴 수 있어요.

2. React Native와 기존 네이티브 간의 성능 체크가 쉽나요

JavaScript Engine으로 동작하는 React Native의 경우 크래시가 발생하거나 느려지는 경우에 디버깅이 매우 어렵습니다. 왜냐하면 기존에 많은 모니터링 도구들이 네이티브에 최적화되거나, 웹뷰에 최적화 되어 있기 때문이죠.

React Native와 네이티브 영역의 모니터링을 함께 해주는 솔루션이 필요하실 수 있어요.

3. React Native는 성능 개선을 해주고 있지만 주기가 느려요

React Native의 패치 버전 반영 주기를 보면 React Native가 매우 활성화되어 있다고 볼 수 있습니다.

React Native의 마이너 버전이 올라갈 경우 많은 API들이 바뀌는 경우가 많습니다. (아무래도 아직 성장하고 있는 프레임워크여서 그럴까요? API들이 자주 변경됩니다.)

그러다 보니 한번 구축한 앱의 React Native 버전을 아주 쉽게 올리는 경우가 적은 거 같습니다. 예를 들어, React Native 0.60.0에서 0.64.0 사이에 다음과 같은 성능 개선이 패치되었는데요.

  • React Native 0.60.0: 이전 버전에 비해 iOS 성능이 2배 이상 개선되었으며, Android 빌드 시간이 매우 줄어들었습니다. 또한, 이전 버전에서 경고로 표시되던 "UI 블록" 문제가 개선되었습니다.
  • React Native 0.61.0: Android에서의 메모리 사용량이 감소하였으며, iOS와 Android 모두에서 향상된 애니메이션 성능이 보입니다. 또한, 새로운 Hermes JavaScript 엔진이 도입되어 빠른 실행 속도와 적은 메모리 사용량을 제공합니다.
  • React Native 0.62.0: Android에서의 레이아웃 속도가 대폭 개선되었으며, iOS와 Android 모두에서 더 높은 프레임 속도를 제공합니다. 또한, 새로운 Autolinking 기능이 도입되어 라이브러리 연결 작업이 자동화됩니다.
  • React Native 0.63.0: iOS와 Android 모두에서 시작 시간이 개선되었습니다. 또한, iOS에서는 큰 번들 파일을 처리할 때의 성능이 개선되었습니다. 또한, Android에서는 네이티브 코드 번들 크기가 감소하고, 다중 Dex 파일이 자동으로 생성되는 기능이 추가되었습니다.
  • React Native 0.64.0: iOS와 Android 모두에서 빌드 시간이 개선되었습니다. 또한, iOS에서는 네이티브 모듈 초기화 시간이 개선되었으며, Android에서는 비트맵 캐시 크기가 자동으로 조정되는 기능이 추가되었습니다.

이렇게 성능 개선이 되었지만 2년 정도의 긴 시간이 걸렸습니다. 분명 React Native 프레임워크는 좋아지고 있지만, 아직 개선되어야 할 부분이 많고, 프레임워크의 개선을 기다리기에는 시간이 오래 걸리죠.

결국 프레임워크 단에서 고쳐주지 못하고 있는 장애와 에러는 개발자가 직접 고쳐야 하는 것이죠.

4. React Native는 OS마다 동작하는 JavaScriptEngine이 달라요

위에서 설명해 드린 듯이 iOS는 JavaScriptCore를, AOS는 V8을 사용합니다. AOT와 JIT을 사용하는 두 OS의 차이를 설명해 드리자면, 여러분들의 코드가 실제 동작하는 데에 있어 최적화되는 방식이 다르다는 것인데요.

따라서 여러분은 1개의 React Native 코드를 작성하여 서비스하고 있지만, 동작이 다른 두 개의 OS의 성능을 체크하셔야 합니다.

마지막으로

이렇게 React Native 앱의 성능 모니터링을 해야만 하는 이유는 너무나 명확한데요. 말씀드린 것처럼 이제 IMQA에서도 여러분의 React Native 앱의 성능을 실시간으로 모니터링하실 수 있습니다. 할까 말까 고민될 땐, 하는 게 정답이죠. (어렵지 않죠?) IMQA는 무료로 모니터링이 가능한 LITE 플랜도 제공하고 있으니 지금 바로 시작해 보세요.

Share on

Tags

IMQA 뉴스레터 구독하기

국내외 다양한 기술 소식을 선별하여 매월 전달해드립니다. IMQA 뉴스레터를 통해 기술 이야기를 함께해보세요.

구독하기