React Native는 크로스 플랫폼 앱 개발의 선두 주자였지만, 기존의 브릿지 기반 설계는 성능과 확장성에서 한계를 보였습니다. 이러한 문제를 해결하기 위해 React Native는 JSI(JavaScript Interface)를
중심으로 새로운 아키텍처를 도입했습니다.
TurboModules, Fabric, Hermes와 같은 기술이 JSI와 결합하여 실제로 어떤 성능적인 변화를 가져왔는지, 그리고 이를 실무에서 어떻게 활용할 수 있는지 살펴보겠습니다.
기존 React Native는 Javascript에서 Native을 호출하기 위해 Bridge를 사용했습니다. Bridge는 Javascript와 Native라는 다른 환경을 이어주는 역할을 하였는데요. 이렇게 다른 환경을 연결하기에 Bridge는 느린 이슈가 있었습니다
Bridge를 사용하면 왜 느려졌으며, JSI를 사용하면 빨라진 이유가 무엇을까요?
이러한 문제는 Javascript와 네이티브라는 다른 환경을 연결하기 위해 발생하던 문제입니다. JSI는 다이렉트로 Javascript와 Native가 연결되기 때문에 위와 같은 문제가 모두 사라지게 되는 원리입니다. 이러한 Bridge와 JSI의 원리를 이해하고 React Native의 변화를 살펴보죠.
기존 React Native에서는 네이티브 모듈이 앱 초기화 단계에서 한꺼번에 로드되었습니다.
TurboModules는 React Native에서 네이티브 모듈의 성능을 개선하기 위해 도입된 새로운 아키텍처입니다. 기존의 네이티브 모듈 방식은 JavaScript와 네이티브 코드 간의 호출에 Bridge를 사용하여 데이터를 전달하고, 이를 직렬화/역직렬화하는 과정에서 성능이 저하되는 문제가 있었는데 TurboModules은 이를 해결하고 성능을 개선합니다.
TurboModule을 사용하려면, 먼저 네이티브 모듈을 새로 구현해야 합니다. 이 모듈은 TurboModule 아키텍처를 사용하여 JavaScript와 네이티브 코드 간의 인터페이스를 정의합니다.
package com.example;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.TurboModule;
import com.facebook.react.bridge.Callback;
public class MyTurboModule implements TurboModule {
private final ReactApplicationContext reactContext;
public MyTurboModule(ReactApplicationContext reactContext) {
this.reactContext = reactContext;
}
@ReactMethod
public void myFunction(String message, Callback successCallback) {
successCallback.invoke("Received: " + message);
}
}
Javascript에서는 다음과 같이 사용할 수 있게 됩니다.
import { NativeModules } from 'react-native';
const { MyTurboModule } = NativeModules;
MyTurboModule.myFunction('Hello from JS', (response) => {
console.log(response); // "Received: Hello from JS"
});
기존 React Native의 UI 렌더링 엔진은 Yoga였습니다. Yoga는 Facebook에서 개발한 레이아웃 엔진으로, React Native에서 UI의 레이아웃을 계산하는 데 사용되었습니다. Yoga는 크로스 플랫폼에서 동일한 레이아웃을 제공하기 위해 설계되었고, 주로 JavaScript에서 계산한 레이아웃 데이터를 네이티브 코드로 전달하는 방식으로 동작했습니다.
하지만, 기존 React Native의 UI 렌더링 엔진에서는 다음과 같은 문제가 있었습니다.
Fabric은 이러한 문제를 해결하기 위해 새롭게 도입된 UI 엔진으로, JSI(JavaScript Interface)를 활용하여 JavaScript와 네이티브 코드 간의 UI 상태를 실시간으로 동기화하고, 레이아웃 계산을 더 효율적으로 처리할 수 있게 만들었습니다.
리스트 렌더링
Fabric은 대규모 리스트를 렌더링할 때도 부드러운 사용자 경험을 제공합니다. 예를 들어, 수천 개의 항목을 포함한 스크롤 리스트에서도 스크롤이 부드럽게 유지됩니다.
<FlatList
data={largeDataset}
renderItem={({ item }) => <ListItem item={item} />}
/>
Fabric을 사용하면 위 코드는 내부적으로 더 최적화되어 작동하며, 스크롤 지연 없이 더 많은 데이터를 처리할 수 있습니다.
기존 React Native는 JSC(JavaScriptCore)나 V8 같은 일반적인 JavaScript 엔진을 사용했지만, 모바일 환경에 최적화되지 않은 부분이 많았습니다.
이를 해결하기 위해 Hermes는 기준문제를 다음과 같이 해결하려고 했습니다.
1. 빠른 앱 시작
Hermes는 앱 초기화 속도를 최적화하여 사용자가 앱을 더 빨리 사용할 수 있게 합니다.
2. 저사양 기기 지원
낮은 메모리 사용량 덕분에 저사양 Android 기기에서도 원활히 실행됩니다. 예를 들어, 동남아 시장을 타겟으로 하는 앱에서 Hermes를 사용하면 시장 점유율을 높이는 데 기여할 수 있습니다.
React Native의 새로운 아키텍처는 JSI와 TurboModules, Fabric, Hermes가 유기적으로 결합하여 다음과 같은 효과를 제공합니다:
React Native는 이제 대규모 애플리케이션에서도 성능 한계를 극복할 수 있는 플랫폼으로 진화했습니다. React Native 뿐만 아니라 다른 하이브리드 프레임워크들도 Bridge를 사용하고 있지만 점차 다른 방법들을 적용해 가고 있는데요. 하이브리드 프레임워크로 만든 앱이 Native만큼의 성능을 뽑아내기 위해 노력하고 있으며, 이번 React Native의 변화도 성능적인 측면에서 주목해야 합니다.