Skip to content

필사 모드: React Native vs Flutter 2025: 크로스플랫폼 모바일 개발의 모든 것

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

목차

1. 2025년 크로스플랫폼 모바일 개발 전망

시장 현황

2025년 모바일 개발 시장에서 크로스플랫폼 프레임워크의 점유율은 계속 증가하고 있습니다. 네이티브 개발 대비 비용 절감과 빠른 출시가 핵심 동기입니다.

| 프레임워크 | GitHub Stars | 주간 다운로드/사용 | 주요 기업 |

|-----------|-------------|-------------------|----------|

| React Native | 120k+ | npm 2M+/주 | Meta, Microsoft, Shopify |

| Flutter | 165k+ | pub.dev 활발 | Google, BMW, Alibaba |

| KMP (Compose) | 성장 중 | JetBrains 생태계 | Netflix, Cash App |

핵심 선택 기준

- **팀 기술 스택**: 웹 개발자 팀이라면 React Native, Dart 학습 의향이 있다면 Flutter

- **UI 커스터마이징**: 플랫폼 네이티브 룩을 원하면 RN, 완전한 커스텀 UI는 Flutter

- **성능 요구사항**: 애니메이션 집약적이면 Flutter, 일반 앱은 둘 다 충분

- **기존 코드**: 웹 코드 재사용은 RN, 새 프로젝트는 Flutter도 좋은 선택

- **채용 시장**: JavaScript 개발자 풀이 넓어 RN이 채용 유리

2. React Native 2025

New Architecture (GA)

React Native의 New Architecture는 2024년에 GA(Generally Available)가 되었고, 2025년에는 사실상 표준이 되었습니다.

**핵심 구성 요소:**

1. **Fabric**: 새로운 렌더링 시스템. 동기식 렌더링으로 UI 응답성 향상

2. **TurboModules**: 네이티브 모듈의 지연 로딩. 앱 시작 시간 단축

3. **JSI (JavaScript Interface)**: JavaScript와 네이티브 코드 간 직접 통신. 브릿지 제거

4. **Codegen**: 타입 안전한 네이티브 코드 자동 생성

// TurboModule 정의 (New Architecture)

export interface Spec extends TurboModule {

getConstants(): {

platform: string;

version: number;

};

multiply(a: number, b: number): Promise<number>;

}

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

Hermes 엔진

Hermes는 React Native의 기본 JavaScript 엔진으로, 모바일 환경에 최적화되었습니다.

- **바이트코드 사전 컴파일**: 앱 시작 시간 단축

- **메모리 효율**: 가비지 컬렉션 최적화

- **크기 감소**: 앱 번들 크기 절감

- **Static Hermes** (실험적): AOT 컴파일로 추가 성능 향상

React Native의 핵심 패턴

// 함수형 컴포넌트 + Hooks

interface User {

id: string;

name: string;

email: string;

}

const UserListScreen: React.FC = () => {

const [users, setUsers] = useState<User[]>([]);

const [refreshing, setRefreshing] = useState(false);

const onRefresh = useCallback(async () => {

setRefreshing(true);

try {

const response = await fetch('https://api.example.com/users');

const data = await response.json();

setUsers(data);

} finally {

setRefreshing(false);

}

}, []);

const renderItem = useCallback(({ item }: { item: User }) => (

), []);

return (

data={users}

renderItem={renderItem}

keyExtractor={(item) => item.id}

refreshing={refreshing}

onRefresh={onRefresh}

/>

);

};

const styles = StyleSheet.create({

card: {

padding: 16,

marginHorizontal: 16,

marginVertical: 8,

backgroundColor: '#fff',

borderRadius: 8,

elevation: 2,

},

name: { fontSize: 18, fontWeight: '600' },

email: { fontSize: 14, color: '#666', marginTop: 4 },

});

3. Flutter 2025

Impeller 렌더링 엔진

Impeller는 Flutter의 새로운 렌더링 엔진으로, Skia를 대체합니다.

**주요 개선사항:**

- **셰이더 사전 컴파일**: 첫 실행 jank(끊김) 제거

- **예측 가능한 성능**: 프레임 드롭 최소화

- **Metal/Vulkan 네이티브**: 플랫폼별 GPU API 직접 활용

- **iOS에서 기본 활성화**, Android에서도 Stable

Dart 3

Dart 3는 Flutter의 개발 경험을 크게 향상시켰습니다.

// 패턴 매칭 (Dart 3)

sealed class Result<T> {

const Result();

}

class Success<T> extends Result<T> {

final T data;

const Success(this.data);

}

class Error<T> extends Result<T> {

final String message;

const Error(this.message);

}

class Loading<T> extends Result<T> {

const Loading();

}

// switch 표현식으로 패턴 매칭

Widget buildContent(Result<User> result) => switch (result) {

Success(:final data) => UserCard(user: data),

Error(:final message) => ErrorWidget(message: message),

Loading() => const CircularProgressIndicator(),

};

// Records

(String name, int age) getUser() => ('Kim', 30);

// 사용

final (name, age) = getUser();

print('$name is $age years old');

// Named fields in records

({String name, int age}) getUserNamed() => (name: 'Kim', age: 30);

Flutter의 핵심 패턴

// StatelessWidget + 상태 관리

class UserListScreen extends StatelessWidget {

const UserListScreen({super.key});

@override

Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(title: const Text('Users')),

body: Consumer<UserNotifier>(

builder: (context, notifier, child) {

return switch (notifier.state) {

LoadingState() => const Center(

child: CircularProgressIndicator(),

),

ErrorState(:final message) => Center(

child: Column(

mainAxisAlignment: MainAxisAlignment.center,

children: [

Text(message),

const SizedBox(height: 16),

ElevatedButton(

onPressed: notifier.retry,

child: const Text('Retry'),

),

],

),

),

SuccessState(:final data) => ListView.builder(

itemCount: data.length,

itemBuilder: (context, index) {

final user = data[index];

return UserCard(user: user);

},

),

};

},

),

);

}

}

class UserCard extends StatelessWidget {

final User user;

const UserCard({super.key, required this.user});

@override

Widget build(BuildContext context) {

return Card(

margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),

child: ListTile(

title: Text(user.name,

style: Theme.of(context).textTheme.titleMedium),

subtitle: Text(user.email),

trailing: const Icon(Icons.chevron_right),

),

);

}

}

4. 기능 비교

성능

| 항목 | React Native | Flutter |

|------|-------------|---------|

| 렌더링 | 네이티브 컴포넌트 | 자체 렌더링 (Impeller) |

| 애니메이션 | Reanimated (60fps) | 내장 (120fps 가능) |

| 앱 시작 시간 | Hermes로 개선됨 | AOT 컴파일로 빠름 |

| 메모리 사용량 | 중간 | 중간~높음 |

| 번들 크기 | 더 작음 (~7MB) | 더 큼 (~15MB) |

| JS 브릿지 | JSI로 제거됨 | 해당 없음 (네이티브) |

개발자 경험 (DX)

| 항목 | React Native | Flutter |

|------|-------------|---------|

| 언어 | JavaScript/TypeScript | Dart |

| Hot Reload | Fast Refresh | Hot Reload/Hot Restart |

| IDE | VS Code, WebStorm | VS Code, Android Studio |

| 디버깅 | Flipper, Chrome DevTools | DevTools, Observatory |

| 패키지 생태계 | npm (방대) | pub.dev (성장 중) |

| 학습 곡선 | 웹 개발자에게 낮음 | Dart 학습 필요 |

네이티브 모듈 통합

| 항목 | React Native | Flutter |

|------|-------------|---------|

| 네이티브 API | TurboModules + JSI | Platform Channels / FFI |

| 카메라 | expo-camera | camera 패키지 |

| 지도 | react-native-maps | google_maps_flutter |

| 푸시 알림 | expo-notifications | firebase_messaging |

| 생체 인증 | expo-local-authentication | local_auth |

5. Expo 딥다이브

Expo 개요

Expo는 React Native 개발을 극적으로 간소화하는 플랫폼입니다. 2025년에는 대부분의 React Native 프로젝트가 Expo를 사용합니다.

Expo Router v4

파일 기반 라우팅으로 Next.js와 유사한 경험을 제공합니다.

app/

_layout.tsx ← 루트 레이아웃

index.tsx ← 홈 화면 (/)

(tabs)/

_layout.tsx ← 탭 네비게이션

home.tsx ← /home

profile.tsx ← /profile

users/

[id].tsx ← /users/123 (동적 라우트)

index.tsx ← /users

settings/

_layout.tsx ← 설정 레이아웃

index.tsx ← /settings

// app/_layout.tsx

export default function RootLayout() {

return (

);

}

// app/users/[id].tsx

export default function UserDetail() {

const { id } = useLocalSearchParams<{ id: string }>();

return (

);

}

// 타입 안전한 네비게이션

function navigateToUser(userId: string) {

router.push(`/users/${userId}`);

}

EAS (Expo Application Services)

EAS Build - 클라우드 빌드

npx eas-cli build --platform ios --profile production

npx eas-cli build --platform android --profile production

EAS Submit - 스토어 제출

npx eas-cli submit --platform ios

npx eas-cli submit --platform android

EAS Update - OTA 업데이트 (코드만)

npx eas-cli update --branch production --message "Bug fix"

Expo SDK 모듈

// expo-camera

function CameraScreen() {

const [permission, requestPermission] = useCameraPermissions();

if (!permission?.granted) {

return <Button title="Grant Permission" onPress={requestPermission} />;

}

return <CameraView style={{ flex: 1 }} facing="back" />;

}

// expo-notifications

async function schedulePushNotification() {

await Notifications.scheduleNotificationAsync({

content: {

title: "Reminder",

body: 'Check your tasks!',

},

trigger: { seconds: 60 },

});

}

6. 성능 벤치마크

앱 시작 시간 (ms)

| 시나리오 | React Native (Hermes) | Flutter (AOT) | Native |

|---------|----------------------|---------------|--------|

| Cold Start (Android) | ~350ms | ~280ms | ~200ms |

| Cold Start (iOS) | ~400ms | ~300ms | ~250ms |

| Warm Start | ~150ms | ~120ms | ~100ms |

스크롤 성능 (FPS)

| 시나리오 | React Native | Flutter |

|---------|-------------|---------|

| 단순 리스트 (1000개) | 58-60 fps | 59-60 fps |

| 이미지 리스트 | 55-60 fps | 58-60 fps |

| 복잡한 카드 레이아웃 | 50-58 fps | 56-60 fps |

애니메이션 성능

| 시나리오 | React Native (Reanimated) | Flutter |

|---------|--------------------------|---------|

| 단순 전환 | 60 fps | 60 fps |

| 복잡한 제스처 | 55-60 fps | 58-60 fps |

| 파티클 시스템 | 45-55 fps | 55-60 fps |

메모리 사용량 (MB)

| 시나리오 | React Native | Flutter |

|---------|-------------|---------|

| 빈 앱 | ~40 MB | ~50 MB |

| 리스트 뷰 (100개) | ~65 MB | ~75 MB |

| 이미지 갤러리 | ~120 MB | ~130 MB |

**결론:** Flutter가 애니메이션/렌더링에서 약간 우위, RN은 메모리와 번들 크기에서 유리. 일반 앱에서는 차이가 미미합니다.

7. 상태 관리

React Native 상태 관리

**Zustand** (가장 인기 있는 선택)

interface UserStore {

users: User[];

isLoading: boolean;

error: string | null;

fetchUsers: () => Promise<void>;

}

const useUserStore = create<UserStore>((set) => ({

users: [],

isLoading: false,

error: null,

fetchUsers: async () => {

set({ isLoading: true, error: null });

try {

const response = await fetch('https://api.example.com/users');

const users = await response.json();

set({ users, isLoading: false });

} catch (error) {

set({ error: (error as Error).message, isLoading: false });

}

},

}));

// 컴포넌트에서 사용

function UserList() {

const { users, isLoading, fetchUsers } = useUserStore();

useEffect(() => {

fetchUsers();

}, [fetchUsers]);

if (isLoading) return <ActivityIndicator />;

return (

data={users}

renderItem={({ item }) => <UserCard user={item} />}

/>

);

}

**TanStack Query (서버 상태)**

function useUsers() {

return useQuery({

queryKey: ['users'],

queryFn: () => fetch('/api/users').then(r => r.json()),

staleTime: 5 * 60 * 1000, // 5분

});

}

function useCreateUser() {

const queryClient = useQueryClient();

return useMutation({

mutationFn: (newUser: CreateUserRequest) =>

fetch('/api/users', {

method: 'POST',

body: JSON.stringify(newUser),

}).then(r => r.json()),

onSuccess: () => {

queryClient.invalidateQueries({ queryKey: ['users'] });

},

});

}

Flutter 상태 관리

**Riverpod** (가장 추천)

// Provider 정의

@riverpod

class UserNotifier extends _$UserNotifier {

@override

FutureOr<List<User>> build() async {

return await ref.read(userRepositoryProvider).getUsers();

}

Future<void> addUser(CreateUserRequest request) async {

state = const AsyncLoading();

state = await AsyncValue.guard(() async {

await ref.read(userRepositoryProvider).createUser(request);

return ref.read(userRepositoryProvider).getUsers();

});

}

}

// 위젯에서 사용

class UserListScreen extends ConsumerWidget {

const UserListScreen({super.key});

@override

Widget build(BuildContext context, WidgetRef ref) {

final usersAsync = ref.watch(userNotifierProvider);

return usersAsync.when(

loading: () => const Center(child: CircularProgressIndicator()),

error: (error, stack) => Center(child: Text('Error: $error')),

data: (users) => ListView.builder(

itemCount: users.length,

itemBuilder: (context, index) => UserCard(user: users[index]),

),

);

}

}

**Bloc** (엔터프라이즈 선택)

// Event

sealed class UserEvent {}

class LoadUsers extends UserEvent {}

class CreateUser extends UserEvent {

final CreateUserRequest request;

CreateUser(this.request);

}

// State

sealed class UserState {}

class UserInitial extends UserState {}

class UserLoading extends UserState {}

class UserLoaded extends UserState {

final List<User> users;

UserLoaded(this.users);

}

class UserError extends UserState {

final String message;

UserError(this.message);

}

// Bloc

class UserBloc extends Bloc<UserEvent, UserState> {

final UserRepository repository;

UserBloc(this.repository) : super(UserInitial()) {

on<LoadUsers>((event, emit) async {

emit(UserLoading());

try {

final users = await repository.getUsers();

emit(UserLoaded(users));

} catch (e) {

emit(UserError(e.toString()));

}

});

}

}

8. 네비게이션

Expo Router (React Native)

// 타입 안전한 라우팅

// app/(tabs)/_layout.tsx

export default function TabLayout() {

return (

name="home"

options={{

title: 'Home',

tabBarIcon: ({ color, size }) => (

),

}}

/>

name="profile"

options={{

title: 'Profile',

tabBarIcon: ({ color, size }) => (

),

}}

/>

);

}

// 딥 링킹 자동 지원

// myapp://users/123 -> app/users/[id].tsx

go_router (Flutter)

final router = GoRouter(

routes: [

ShellRoute(

builder: (context, state, child) => ScaffoldWithNavBar(child: child),

routes: [

GoRoute(

path: '/',

builder: (context, state) => const HomeScreen(),

),

GoRoute(

path: '/users',

builder: (context, state) => const UserListScreen(),

routes: [

GoRoute(

path: ':id',

builder: (context, state) {

final id = state.pathParameters['id']!;

return UserDetailScreen(userId: id);

},

),

],

),

GoRoute(

path: '/profile',

builder: (context, state) => const ProfileScreen(),

),

],

),

],

);

// 사용

context.go('/users/123');

context.push('/users/123');

context.pop();

9. 테스팅

React Native 테스팅

**Detox (E2E)**

// e2e/users.test.ts

describe('User Flow', () => {

beforeAll(async () => {

await device.launchApp();

});

it('should show user list', async () => {

await expect(element(by.id('user-list'))).toBeVisible();

});

it('should navigate to user detail', async () => {

await element(by.id('user-card-1')).tap();

await expect(element(by.text('User Detail'))).toBeVisible();

});

it('should pull to refresh', async () => {

await element(by.id('user-list')).swipe('down');

await waitFor(element(by.id('loading-indicator')))

.not.toBeVisible()

.withTimeout(5000);

});

});

**Maestro (간편한 E2E)**

.maestro/user-flow.yaml

appId: com.example.myapp

- launchApp

- assertVisible: "Users"

- tapOn: "Kim"

- assertVisible: "User Detail"

- back

- assertVisible: "Users"

Flutter 테스팅

**Widget Test**

void main() {

testWidgets('UserCard displays user info', (tester) async {

final user = User(id: '1', name: 'Kim', email: 'kim@test.com');

await tester.pumpWidget(

MaterialApp(home: UserCard(user: user)),

);

expect(find.text('Kim'), findsOneWidget);

expect(find.text('kim@test.com'), findsOneWidget);

});

testWidgets('UserListScreen shows loading indicator', (tester) async {

await tester.pumpWidget(

const MaterialApp(home: UserListScreen()),

);

expect(find.byType(CircularProgressIndicator), findsOneWidget);

});

}

**Integration Test**

// integration_test/app_test.dart

void main() {

IntegrationTestWidgetsFlutterBinding.ensureInitialized();

testWidgets('full user flow test', (tester) async {

await tester.pumpWidget(const MyApp());

await tester.pumpAndSettle();

// 사용자 목록 확인

expect(find.text('Users'), findsOneWidget);

// 사용자 카드 탭

await tester.tap(find.text('Kim'));

await tester.pumpAndSettle();

// 상세 화면 확인

expect(find.text('User Detail'), findsOneWidget);

});

}

**Patrol (고급 E2E)**

void main() {

patrolTest('User flow with native interactions', ($) async {

await $.pumpWidgetAndSettle(const MyApp());

// 권한 대화상자 처리

await $.native.grantPermissionWhenInUse();

// Flutter 위젯과 네이티브 UI 모두 테스트

await $(#userList).scrollTo(find.text('Kim'));

await $(find.text('Kim')).tap();

});

}

10. 채용 시장과 급여

2025년 시장 현황

| 지표 | React Native | Flutter |

|------|-------------|---------|

| LinkedIn 공고 (글로벌) | 약 35,000+ | 약 25,000+ |

| 한국 공고 | 약 800+ | 약 500+ |

| 평균 연봉 (미국) | 약 13만~17만 달러 | 약 12만~16만 달러 |

| 평균 연봉 (한국) | 약 5,500만~8,500만 원 | 약 5,000만~8,000만 원 |

| 프리랜서 시급 (미국) | 약 80~150 달러 | 약 70~130 달러 |

어떤 것을 먼저 배울까

**React Native을 먼저 배워야 하는 경우:**

- 이미 JavaScript/TypeScript를 알고 있음

- 웹 개발 경험이 있음

- 빠른 취업이 목표

- 기존 React 웹 프로젝트와 코드 공유하고 싶음

**Flutter를 먼저 배워야 하는 경우:**

- 프로그래밍을 처음 시작

- 커스텀 UI/애니메이션이 중요한 프로젝트

- 데스크톱/웹까지 하나의 코드로 지원하고 싶음

- Google 생태계에 관심

11. 프로젝트별 선택 프레임워크

의사 결정 플로우차트

**1. 팀이 JavaScript/TypeScript에 익숙한가?**

- Yes → React Native 우선 고려

- No → 계속 평가

**2. 복잡한 커스텀 UI/애니메이션이 핵심인가?**

- Yes → Flutter 우선 고려

- No → 계속 평가

**3. 웹 코드를 공유해야 하는가?**

- Yes → React Native (React 코드 공유)

- No → 계속 평가

**4. 데스크톱 지원이 필요한가?**

- Yes → Flutter (더 성숙한 데스크톱 지원)

- No → 프로젝트 요구사항에 따라 선택

프로젝트 유형별 추천

| 프로젝트 유형 | 추천 | 이유 |

|-------------|------|------|

| E-커머스 앱 | React Native | 웹과 코드 공유, Shopify 연동 |

| 소셜 미디어 | Flutter | 커스텀 UI, 애니메이션 |

| 핀테크 앱 | React Native | 큰 JavaScript 생태계 |

| 게임 | Flutter | 커스텀 렌더링 강점 |

| 기업용 앱 | React Native | 채용 용이성 |

| IoT 대시보드 | Flutter | 데스크톱 + 모바일 통합 |

| MVP/스타트업 | Expo (RN) | 가장 빠른 개발 속도 |

| 미디어/스트리밍 | Flutter | 성능 최적화 |

12. 인터뷰 질문과 퀴즈

인터뷰 질문 10선

**Q1: React Native New Architecture의 핵심 구성 요소를 설명하세요.**

New Architecture는 Fabric(새 렌더링 시스템), TurboModules(네이티브 모듈 지연 로딩), JSI(JavaScript Interface)로 구성됩니다. JSI는 기존 브릿지를 대체하여 JavaScript와 네이티브 코드 간 직접 동기 통신을 가능하게 합니다. Codegen은 타입 안전한 네이티브 인터페이스를 자동 생성합니다.

**Q2: Flutter의 Impeller가 Skia를 대체한 이유는?**

Skia 기반 렌더링은 셰이더 컴파일을 런타임에 수행하여 첫 프레임에서 jank(끊김)가 발생했습니다. Impeller는 셰이더를 빌드 타임에 사전 컴파일하여 이 문제를 해결합니다. Metal(iOS)과 Vulkan(Android)을 직접 사용하여 예측 가능한 성능을 제공합니다.

**Q3: React Native와 Flutter의 렌더링 방식 차이는?**

React Native는 플랫폼의 네이티브 UI 컴포넌트를 사용합니다(UIKit/Android Views). 따라서 플랫폼 룩앤필을 자연스럽게 따릅니다. Flutter는 자체 렌더링 엔진(Impeller)으로 모든 픽셀을 직접 그립니다. 완전한 UI 커스터마이징이 가능하지만 네이티브 룩 구현에 추가 작업이 필요합니다.

**Q4: Expo의 장점과 한계를 설명하세요.**

장점: EAS Build로 CI/CD 간소화, OTA 업데이트(EAS Update), 파일 기반 라우팅(Expo Router), 풍부한 SDK 모듈, Prebuild로 네이티브 코드 관리 자동화. 한계: 일부 네이티브 모듈 미지원 시 config plugin 또는 eject 필요, 빌드 시간이 로컬보다 길 수 있음.

**Q5: Flutter에서 Riverpod를 Provider보다 선호하는 이유는?**

Riverpod는 컴파일 타임 안전성(런타임 에러 감소), BuildContext 의존성 제거, 프로바이더 간 의존성을 명시적으로 관리, 테스트 용이성(오버라이드 지원), autodispose로 자동 메모리 관리를 제공합니다. Provider의 한계(런타임 에러, 유연성 부족)를 해결한 진화된 버전입니다.

**Q6: React Native에서 성능 최적화 방법을 설명하세요.**

FlatList 사용(가상화 스크롤), React.memo/useMemo/useCallback으로 불필요한 리렌더링 방지, Reanimated로 UI 스레드 애니메이션, Hermes 엔진 활성화, 이미지 최적화(캐싱, 리사이징), 번들 분석으로 불필요한 의존성 제거, New Architecture(JSI) 활성화.

**Q7: Dart 3의 패턴 매칭과 Records가 Flutter에 미친 영향은?**

패턴 매칭으로 sealed class와 switch 표현식 결합 시 타입 안전한 상태 처리가 가능합니다. Records는 여러 값을 반환하는 함수를 간결하게 만듭니다. 이 조합으로 Flutter의 상태 관리 코드가 더 안전하고 읽기 쉬워졌습니다.

**Q8: React Native와 Flutter 중 하나를 선택해야 한다면, 결정 기준은?**

팀 기술 스택(JS 경험이면 RN), UI 요구사항(커스텀 UI면 Flutter), 코드 공유 전략(웹 공유면 RN), 채용 시장(JS 개발자 풀이 넓음), 성능 요구사항(그래픽 집약적이면 Flutter), 기존 인프라(React 웹이 있으면 RN). 대부분의 일반 앱에서는 큰 차이가 없으므로 팀 역량이 가장 중요합니다.

**Q9: 크로스플랫폼 앱에서 네이티브 기능 접근 방법을 비교하세요.**

React Native: TurboModules + JSI로 네이티브 코드(Java/Kotlin, ObjC/Swift)와 직접 통신합니다. Expo는 config plugin으로 네이티브 설정을 관리합니다. Flutter: Platform Channels(메서드/이벤트 채널)로 비동기 통신하거나, FFI로 C 라이브러리를 직접 호출합니다. 두 프레임워크 모두 대부분의 네이티브 API를 커버합니다.

**Q10: 크로스플랫폼 테스팅 전략을 설명하세요.**

단위 테스트(비즈니스 로직), 위젯/컴포넌트 테스트(UI), 통합 테스트(사용자 시나리오), E2E 테스트(실제 디바이스)의 테스트 피라미드를 따릅니다. RN에서는 Jest + Testing Library + Detox/Maestro, Flutter에서는 test + widget test + integration_test + Patrol을 사용합니다.

퀴즈 5선

**정답:**

JSI(JavaScript Interface)는 JavaScript와 네이티브 코드 간의 직접적인 동기 통신을 가능하게 하는 인터페이스입니다. 기존의 비동기 JSON 직렬화 브릿지를 대체합니다. C++로 작성되어 JavaScript 엔진에 독립적이며, JavaScript에서 C++ 객체를 직접 참조할 수 있습니다. 이를 통해 성능이 크게 향상되고, TurboModules와 Fabric의 기반 기술이 됩니다.

**정답:**

StatelessWidget은 내부 상태가 없는 위젯에 사용합니다. 부모로부터 받은 데이터만 표시하며 리빌드 시 항상 같은 결과를 반환합니다. StatefulWidget은 내부에서 변경 가능한 상태가 필요할 때 사용합니다. 그러나 2025년에는 Riverpod이나 Bloc 같은 상태 관리 라이브러리 사용이 일반적이므로, 대부분의 위젯을 StatelessWidget + 상태 관리 라이브러리 조합으로 작성합니다.

**정답:**

React Navigation은 명시적으로 네비게이터와 스크린을 코드로 정의합니다. 타입 정의가 별도로 필요하고 중첩이 복잡해질 수 있습니다. Expo Router는 Next.js처럼 파일 시스템 구조가 곧 라우트입니다. 자동 딥 링킹, 타입 추론, 레이아웃 시스템을 제공하며, 웹과 모바일에서 동일한 URL 구조를 사용할 수 있습니다.

**정답:**

Hermes는 모바일 환경에 최적화된 JavaScript 엔진입니다. JavaScript를 바이트코드로 사전 컴파일(AOT)하여 앱 시작 시 파싱 시간을 제거합니다. 가비지 컬렉션이 모바일에 최적화되어 메모리 사용량이 적습니다. 앱 번들 크기도 더 작습니다. V8이나 JavaScriptCore는 범용 엔진이지만 Hermes는 모바일 React Native에 특화되어 있습니다.

**정답:**

Flutter의 Hot Reload는 Dart VM에서 변경된 소스 코드를 주입하고 위젯 트리를 리빌드합니다. 상태가 보존되어 UI 변경을 즉시 확인할 수 있습니다. React Native의 Fast Refresh는 React 컴포넌트를 핫 스와핑하여 상태를 유지하면서 UI를 업데이트합니다. 두 방식 모두 앱 재시작 없이 변경사항을 반영하지만, Flutter는 VM 레벨에서, RN은 번들러(Metro) 레벨에서 동작합니다.

참고 자료

1. [React Native 공식 문서](https://reactnative.dev/) - 프레임워크 가이드

2. [Flutter 공식 문서](https://flutter.dev/) - 프레임워크 가이드

3. [Expo 문서](https://docs.expo.dev/) - Expo 플랫폼 가이드

4. [React Native New Architecture](https://reactnative.dev/docs/the-new-architecture/landing-page) - 새 아키텍처 가이드

5. [Flutter Impeller](https://docs.flutter.dev/perf/impeller) - 임펠러 렌더링 엔진

6. [Dart 공식 문서](https://dart.dev/) - Dart 언어 가이드

7. [Expo Router](https://docs.expo.dev/router/introduction/) - 파일 기반 라우팅

8. [Riverpod](https://riverpod.dev/) - Flutter 상태 관리

9. [Zustand](https://docs.pmnd.rs/zustand) - React 상태 관리

10. [TanStack Query](https://tanstack.com/query) - 서버 상태 관리

11. [Detox](https://wix.github.io/Detox/) - React Native E2E 테스팅

12. [Patrol](https://patrol.leancode.co/) - Flutter 고급 테스팅

13. [go_router](https://pub.dev/packages/go_router) - Flutter 네비게이션

14. [Reanimated](https://docs.swmansion.com/react-native-reanimated/) - RN 애니메이션 라이브러리

현재 단락 (1/594)

2025년 모바일 개발 시장에서 크로스플랫폼 프레임워크의 점유율은 계속 증가하고 있습니다. 네이티브 개발 대비 비용 절감과 빠른 출시가 핵심 동기입니다.

작성 글자: 0원문 글자: 17,098작성 단락: 0/594