[G1-Sync] Manual knowledge update
This commit is contained in:
@@ -0,0 +1,265 @@
|
||||
---
|
||||
id: mobile-rn-new-architecture
|
||||
title: React Native New Architecture — Fabric / TurboModule / JSI
|
||||
category: Coding
|
||||
status: draft
|
||||
source_trust_level: B
|
||||
verification_status: conceptual
|
||||
created_at: 2026-05-09
|
||||
updated_at: 2026-05-09
|
||||
tags: [react-native, fabric, turbomodule, jsi, vibe-coding]
|
||||
tech_stack: { language: "TS / Swift / Kotlin", applicable_to: ["React Native"] }
|
||||
applied_in: []
|
||||
aliases: [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 완전 제거.
|
||||
|
||||
## 💻 코드 패턴
|
||||
|
||||
### 활성화
|
||||
```jsonc
|
||||
// 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)
|
||||
```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 실행
|
||||
```bash
|
||||
# iOS
|
||||
npx pod-install
|
||||
# Codegen 자동 실행
|
||||
|
||||
# Android
|
||||
cd android && ./gradlew generateCodegenArtifactsFromSchemas
|
||||
```
|
||||
|
||||
→ Auto-generate Objective-C++ / Java interface.
|
||||
|
||||
### iOS — Swift 구현
|
||||
```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 구현
|
||||
```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)
|
||||
```ts
|
||||
// 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');
|
||||
```
|
||||
|
||||
```swift
|
||||
// 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 — 큰 데이터)
|
||||
```cpp
|
||||
// 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 = 빠른 시작
|
||||
+ 작은 메모리
|
||||
+ 정적 분석 친화
|
||||
```
|
||||
|
||||
```jsonc
|
||||
// metro.config.js
|
||||
hermesEnabled: true
|
||||
```
|
||||
|
||||
### Concurrent React 활용 (Fabric)
|
||||
```tsx
|
||||
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 가 표준.
|
||||
|
||||
## 🔗 관련 문서
|
||||
- [[RN_Native_Module_Bridging]]
|
||||
- [[RN_Hermes_Optimization]]
|
||||
- [[React_Native_Bridge_Performance]]
|
||||
Reference in New Issue
Block a user