Files
2nd/10_Wiki/Topics/Coding/Mobile_RN_New_Architecture.md
T
2026-05-09 21:08:02 +09:00

6.7 KiB

id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
id title category status source_trust_level verification_status created_at updated_at tags tech_stack applied_in aliases
mobile-rn-new-architecture React Native New Architecture — Fabric / TurboModule / JSI Coding draft B conceptual 2026-05-09 2026-05-09
react-native
fabric
turbomodule
jsi
vibe-coding
language applicable_to
TS / Swift / Kotlin
React Native
Fabric
TurboModule
JSI
Codegen
Bridgeless
Hermes

RN New Architecture (2024+)

옛 Bridge → JSI 직접 호출. Fabric (rendering) + TurboModule (native module) + Codegen (type-safe). 0.74+ default. 빠르고 type-safe.

📖 핵심 개념

  • JSI (JavaScript Interface): JS ↔ native 직접 binding (bridge X).
  • Fabric: 새 renderer, concurrent React 호환.
  • TurboModule: lazy 로드 + sync 호출 가능.
  • Codegen: TS spec → C++/Swift/Kotlin 인터페이스 자동.
  • Bridgeless: 옛 bridge 완전 제거.

💻 코드 패턴

활성화

// react-native.config.js / package.json
"reactNativeArchVersion": "new",

// iOS — Podfile
:fabric_enabled => true,
:hermes_enabled => true,
:new_arch_enabled => true,

// Android — gradle.properties
newArchEnabled=true
hermesEnabled=true

TurboModule spec (TS)

// specs/NativeBattery.ts
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';

export interface Spec extends TurboModule {
  // sync methods 가능
  getBatteryLevel(): number;
  
  // async (Promise)
  getInfo(): Promise<{ level: number; charging: boolean }>;
  
  // void
  setBrightness(value: number): void;
  
  // Event listener
  readonly addListener: (eventType: string) => void;
  readonly removeListeners: (count: number) => void;
}

export default TurboModuleRegistry.getEnforcing<Spec>('NativeBattery');

Codegen 실행

# iOS
npx pod-install
# Codegen 자동 실행

# Android
cd android && ./gradlew generateCodegenArtifactsFromSchemas

→ Auto-generate Objective-C++ / Java interface.

iOS — Swift 구현

@objc(NativeBattery)
class NativeBattery: NSObject {
    @objc static func requiresMainQueueSetup() -> Bool { false }
    
    @objc func getBatteryLevel() -> NSNumber {
        UIDevice.current.isBatteryMonitoringEnabled = true
        return NSNumber(value: UIDevice.current.batteryLevel)
    }
    
    @objc(getInfoWithResolver:rejecter:)
    func getInfo(resolve: @escaping RCTPromiseResolveBlock,
                 reject: @escaping RCTPromiseRejectBlock) {
        // ...
    }
}

Android — Kotlin 구현

class NativeBatteryModule(reactContext: ReactApplicationContext) :
    NativeBatterySpec(reactContext) {
    
    override fun getName() = "NativeBattery"
    
    override fun getBatteryLevel(): Double {
        val bm = reactApplicationContext.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
        return bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) / 100.0
    }
    
    override fun getInfo(promise: Promise) {
        // ...
    }
}

Fabric Component (native UI)

// CustomViewNativeComponent.ts
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
import type { ViewProps } from 'react-native';
import type { Float, Int32 } from 'react-native/Libraries/Types/CodegenTypes';

export interface NativeProps extends ViewProps {
  color?: string;
  size?: Float;
}

export default codegenNativeComponent<NativeProps>('CustomView');
// iOS Fabric component
class CustomViewComponentView: RCTViewComponentView {
    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = .red
    }
    
    override func updateProps(_ props: Props, oldProps: Props) {
        let newProps = Self.componentDescriptorProvider().rawProps(from: props)
        // apply
        super.updateProps(props, oldProps: oldProps)
    }
}

JSI direct binding (advanced — 큰 데이터)

// C++
#include <jsi/jsi.h>

void install(jsi::Runtime& rt) {
    auto myFn = jsi::Function::createFromHostFunction(
        rt,
        jsi::PropNameID::forAscii(rt, "myFn"),
        1,
        [](jsi::Runtime& rt, const jsi::Value& thisValue, const jsi::Value* args, size_t count) -> jsi::Value {
            // 직접 처리 — bridge 없음
            return jsi::Value(42);
        }
    );
    rt.global().setProperty(rt, "myFn", myFn);
}

→ 매우 hot path 만 (보통 TurboModule 충분).

Hermes (JS engine)

Default JS engine = Hermes (vs JSC).
+ Bytecode pre-compile = 빠른 시작
+ 작은 메모리
+ 정적 분석 친화
// metro.config.js
hermesEnabled: true

Concurrent React 활용 (Fabric)

import { startTransition } from 'react';

// State update 분리
startTransition(() => {
  setHeavyState(newValue);
});

// useDeferredValue
const deferred = useDeferredValue(input);

→ 무거운 업데이트가 input 안 막음.

Performance (구 vs 신)

옛 Bridge:
- JS ↔ Native = JSON serialize
- Async only
- Bridge contention

JSI / TurboModule:
- 직접 binding
- Sync 가능
- Lazy load (사용 시)
- Codegen = type-safe

→ 50-100ms 시작 절감, 일부 동기 작업 10x 빠름.

Migration 옛 module → TurboModule

1. TS spec 정의
2. Codegen 실행
3. Native 구현 (NativeXxxSpec extend)
4. NativeModules.X → TurboModuleRegistry.get('X')

디버깅

Flipper (RN built-in) — deprecated.
새 = React DevTools + 별 도구.

Hermes profiler:
$ adb shell am profile com.app start

Common 문제

1. Pod install 실패 → cd ios; pod install --repo-update
2. Codegen 결과 mismatch → clean build, ios/build, android/.gradle 삭제
3. Hermes bytecode 호환 안 — RN version 업데이트 동기
4. Native module 못 찾음 → autolinking 확인 + spec 의 module 이름 일치

🤔 의사결정 기준

상황 추천
새 RN 프로젝트 New arch + Hermes default
기존 옛 arch 0.74+ migration
Sync 호출 필요 (battery, device) TurboModule
Native UI custom Fabric Component
매우 hot path JSI direct
단순 native logic TurboModule 충분

안티패턴

  • 옛 NativeModule + 새 arch: 호환성 문제. 변환.
  • Sync TurboModule + 무거운 작업: UI 막음. async.
  • Codegen 결과 commit X: CI 빌드 필요.
  • JSI 직접 + 잘못된 lifetime: crash. weak ref.
  • TurboModule 가 ReactApplicationContext 사용: thread 주의.
  • iOS / Android 구현 비대칭: cross-platform 깨짐.

🤖 LLM 활용 힌트

  • 새 RN = New arch default.
  • TurboModule + Codegen 으로 type-safe.
  • Sync 가능 = battery / config — 적극 활용.
  • Hermes 가 표준.

🔗 관련 문서