React Native에 대해서
React Native란?
React Native는 Facebook(현 Meta)에서 개발한 오픈소스 모바일 애플리케이션 프레임워크이다. JavaScript와 React를 사용하여 iOS와 Android 앱을 동시에 개발할 수 있게 해준다.
React Native의 특징
크로스 플랫폼 개발
- 하나의 코드베이스로 iOS와 Android 앱 동시 개발
- 대부분의 코드를 공유하여 개발 시간 단축
네이티브 성능
- JavaScript 브리지를 통해 네이티브 컴포넌트와 통신
- 네이티브 UI 컴포넌트를 직접 렌더링
Hot Reloading
- 코드 변경 시 즉시 반영
- 앱을 재시작하지 않고도 변경사항 확인 가능
커뮤니티와 생태계
- 풍부한 라이브러리와 패키지
- 활발한 커뮤니티 지원
React와 React Native의 차이점
주요 차이점
| 항목 | React (Web) | React Native |
|---|---|---|
| 렌더링 대상 | DOM 요소 | 네이티브 컴포넌트 |
| 스타일링 | CSS | StyleSheet API |
| 레이아웃 | CSS Flexbox/Grid | Flexbox만 지원 |
| 네비게이션 | React Router | React Navigation 등 |
| 플랫폼 | 브라우저 | iOS/Android |
컴포넌트 차이
// React (Web)
import React from "react";
function App() {
return (
<div>
<h1>Hello World</h1>
<button onClick={() => alert("Clicked")}>Click me</button>
</div>
);
}
// React Native
import React from "react";
import { View, Text, TouchableOpacity, Alert } from "react-native";
function App() {
return (
<View>
<Text>Hello World</Text>
<TouchableOpacity onPress={() => Alert.alert("Clicked")}>
<Text>Click me</Text>
</TouchableOpacity>
</View>
);
}
개발 환경 설정
필수 요구사항
- Node.js (v14 이상)
- npm 또는 yarn
- React Native CLI
- 플랫폼별 도구
- iOS: Xcode (macOS만)
- Android: Android Studio, JDK
React Native CLI 설치
npm install -g react-native-cli
새 프로젝트 생성
# React Native CLI 사용
npx react-native init MyApp
# 또는 Expo 사용 (권장)
npx create-expo-app MyApp
Expo vs React Native CLI
Expo
장점:
- 빠른 시작과 간편한 설정
- OTA(Over-The-Air) 업데이트 지원
- 다양한 내장 API 제공
- 개발 빌드 없이 바로 테스트 가능
단점:
- 네이티브 모듈 추가 시 제한적
- 앱 크기가 상대적으로 큼
React Native CLI
장점:
- 완전한 네이티브 모듈 접근
- 더 작은 앱 크기
- 더 많은 커스터마이징 가능
단점:
- 복잡한 설정 과정
- 네이티브 코드 수정 필요 시 지식 필요
기본 컴포넌트
View
div와 유사한 컨테이너 컴포넌트:
import { View } from "react-native";
<View style={{ flex: 1, padding: 20 }}>
<Text>Content</Text>
</View>;
Text
텍스트를 표시하는 컴포넌트:
import { Text } from "react-native";
<Text style={{ fontSize: 18, fontWeight: "bold" }}>Hello React Native</Text>;
Image
이미지를 표시하는 컴포넌트:
import { Image } from "react-native";
// 로컬 이미지
<Image source={require("./assets/logo.png")} />
// 네트워크 이미지
<Image
source={{ uri: "https://example.com/image.jpg" }}
style={{ width: 200, height: 200 }}
/>
// 리사이즈 모드
<Image
source={require("./assets/logo.png")}
resizeMode="contain"
/>
ScrollView
스크롤 가능한 컨테이너:
import { ScrollView, Text } from "react-native";
<ScrollView>
<Text>Item 1</Text>
<Text>Item 2</Text>
<Text>Item 3</Text>
</ScrollView>;
FlatList
성능 최적화된 리스트 컴포넌트:
import { FlatList, Text } from "react-native";
const data = [
{ id: "1", title: "Item 1" },
{ id: "2", title: "Item 2" },
{ id: "3", title: "Item 3" },
];
<FlatList
data={data}
keyExtractor={(item) => item.id}
renderItem={({ item }) => <Text>{item.title}</Text>}
/>;
TouchableOpacity / Pressable
터치 가능한 컴포넌트:
import { TouchableOpacity, Pressable, Text } from "react-native";
// TouchableOpacity (권장하지 않음, Pressable 사용 권장)
<TouchableOpacity onPress={() => console.log("Pressed")}>
<Text>Button</Text>
</TouchableOpacity>
// Pressable (권장)
<Pressable
onPress={() => console.log("Pressed")}
onPressIn={() => console.log("Press In")}
onPressOut={() => console.log("Press Out")}
>
<Text>Button</Text>
</Pressable>
스타일링
StyleSheet API
import { StyleSheet, View, Text } from "react-native";
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
title: {
fontSize: 24,
fontWeight: "bold",
color: "#333",
},
});
function App() {
return (
<View style={styles.container}>
<Text style={styles.title}>Hello</Text>
</View>
);
}
Flexbox 레이아웃
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: "row", // 'column' (기본값) 또는 'row'
justifyContent: "center", // 주축 정렬
alignItems: "center", // 교차축 정렬
},
box: {
width: 100,
height: 100,
backgroundColor: "blue",
margin: 10,
},
});
주요 스타일 속성
- 레이아웃:
flex,flexDirection,justifyContent,alignItems - 크기:
width,height,minWidth,maxHeight - 여백:
margin,marginTop,padding,paddingHorizontal - 테두리:
borderWidth,borderColor,borderRadius - 색상:
backgroundColor,color - 텍스트:
fontSize,fontWeight,textAlign
상태 관리
useState Hook
import React, { useState } from "react";
import { View, Text, Button } from "react-native";
function Counter() {
const [count, setCount] = useState(0);
return (
<View>
<Text>Count: {count}</Text>
<Button title="Increment" onPress={() => setCount(count + 1)} />
</View>
);
}
Context API
import React, { createContext, useContext, useState } from "react";
const ThemeContext = createContext();
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState("light");
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
}
export function useTheme() {
return useContext(ThemeContext);
}
Redux / Zustand
# Redux Toolkit
npm install @reduxjs/toolkit react-redux
# Zustand
npm install zustand
네비게이션
React Navigation
가장 널리 사용되는 네비게이션 라이브러리:
npm install @react-navigation/native
npm install @react-navigation/stack
npm install react-native-screens react-native-safe-area-context
import { NavigationContainer } from "@react-navigation/native";
import { createStackNavigator } from "@react-navigation/stack";
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
function HomeScreen({ navigation }) {
return (
<View>
<Button
title="Go to Details"
onPress={() => navigation.navigate("Details")}
/>
</View>
);
}
탭 네비게이션
npm install @react-navigation/bottom-tabs
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
const Tab = createBottomTabNavigator();
function MyTabs() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
);
}
네이티브 모듈
네이티브 모듈 생성 (Android)
// android/app/src/main/java/com/myapp/ToastModule.java
package com.myapp;
import android.widget.Toast;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
public class ToastModule extends ReactContextBaseJavaModule {
@Override
public String getName() {
return "ToastModule";
}
@ReactMethod
public void show(String message) {
Toast.makeText(getReactApplicationContext(), message, Toast.LENGTH_SHORT).show();
}
}
JavaScript에서 사용
import { NativeModules } from "react-native";
const { ToastModule } = NativeModules;
ToastModule.show("Hello from Native!");
API 호출
Fetch API
import { useState, useEffect } from "react";
import { View, Text, FlatList } from "react-native";
function UsersList() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch("https://api.example.com/users")
.then((response) => response.json())
.then((data) => {
setUsers(data);
setLoading(false);
})
.catch((error) => {
console.error(error);
setLoading(false);
});
}, []);
if (loading) {
return <Text>Loading...</Text>;
}
return (
<FlatList
data={users}
keyExtractor={(item) => item.id.toString()}
renderItem={({ item }) => <Text>{item.name}</Text>}
/>
);
}
Axios 사용
npm install axios
import axios from "axios";
const fetchUsers = async () => {
try {
const response = await axios.get("https://api.example.com/users");
return response.data;
} catch (error) {
console.error(error);
throw error;
}
};
성능 최적화
FlatList 최적화
<FlatList
data={items}
keyExtractor={(item) => item.id}
renderItem={renderItem}
removeClippedSubviews={true} // 화면 밖 항목 제거
maxToRenderPerBatch={10} // 한 번에 렌더링할 항목 수
windowSize={10} // 렌더링할 윈도우 크기
initialNumToRender={10} // 초기 렌더링 항목 수
/>
메모이제이션
import React, { memo, useMemo, useCallback } from "react";
const Item = memo(({ item, onPress }) => {
return (
<Pressable onPress={() => onPress(item.id)}>
<Text>{item.title}</Text>
</Pressable>
);
});
function List({ items }) {
const handlePress = useCallback((id) => {
console.log("Pressed:", id);
}, []);
const sortedItems = useMemo(() => {
return [...items].sort((a, b) => a.title.localeCompare(b.title));
}, [items]);
return (
<FlatList
data={sortedItems}
renderItem={({ item }) => <Item item={item} onPress={handlePress} />}
/>
);
}
이미지 최적화
import { Image } from "react-native";
<Image
source={{ uri: imageUrl }}
style={{ width: 200, height: 200 }}
resizeMode="cover"
// 캐싱 최적화
cache="force-cache"
/>;
디버깅
React Native Debugger
npm install -g react-native-debugger
Flipper
Facebook에서 개발한 디버깅 도구:
# 자동으로 설치됨 (React Native 0.62+)
콘솔 로그
import { LogBox } from "react-native";
// 특정 경고 숨기기
LogBox.ignoreLogs(["Warning: ..."]);
// 모든 경고 숨기기 (권장하지 않음)
LogBox.ignoreAllLogs();
빌드 및 배포
Android APK 빌드
cd android
./gradlew assembleRelease
iOS 빌드
cd ios
pod install
# Xcode에서 Archive 생성
Expo 빌드
# Android
eas build --platform android
# iOS
eas build --platform ios
자주 사용하는 라이브러리
UI 라이브러리
- React Native Elements: UI 컴포넌트 라이브러리
- NativeBase: 크로스 플랫폼 UI 프레임워크
- React Native Paper: Material Design 컴포넌트
상태 관리
- Redux Toolkit: 예측 가능한 상태 관리
- Zustand: 가벼운 상태 관리
- MobX: 반응형 상태 관리
네비게이션
- React Navigation: 가장 인기 있는 네비게이션 라이브러리
- React Native Navigation: 네이티브 네비게이션
폼 관리
- React Hook Form: 성능 최적화된 폼 관리
- Formik: 폼 상태 관리
네트워킹
- Axios: HTTP 클라이언트
- Apollo Client: GraphQL 클라이언트
주의사항 및 모범 사례
플랫폼별 코드 작성
import { Platform } from "react-native"; const styles = StyleSheet.create({ container: { paddingTop: Platform.OS === "ios" ? 20 : 0, }, });안전 영역 처리
import { SafeAreaView } from "react-native-safe-area-context"; <SafeAreaView style={{ flex: 1 }}>{/* Content */}</SafeAreaView>;성능 모니터링
- React DevTools Profiler 사용
- Flipper Performance Monitor 활용
에러 처리
import { ErrorBoundary } from "react-error-boundary"; function ErrorFallback({ error }) { return <Text>Something went wrong: {error.message}</Text>; } <ErrorBoundary FallbackComponent={ErrorFallback}> <App /> </ErrorBoundary>;테스트 작성
npm install --save-dev @testing-library/react-native
React Native vs Flutter vs Native
| 항목 | React Native | Flutter | Native |
|---|---|---|---|
| 언어 | JavaScript/TypeScript | Dart | Swift/Kotlin |
| 성능 | 좋음 | 매우 좋음 | 최고 |
| 개발 속도 | 빠름 | 빠름 | 느림 |
| 코드 공유 | 높음 | 높음 | 없음 |
| 커뮤니티 | 매우 큼 | 큼 | 플랫폼별 |
| 네이티브 접근 | 제한적 | 제한적 | 완전 |
결론
React Native는 웹 개발 지식을 활용해 모바일 앱을 개발할 수 있게 해주는 강력한 프레임워크이다. 크로스 플랫폼 개발의 이점과 풍부한 생태계를 통해 빠르게 모바일 앱을 구축할 수 있다. 하지만 네이티브 모듈이나 복잡한 기능이 필요한 경우 추가적인 학습과 설정이 필요하다. 프로젝트의 요구사항과 팀의 기술 스택을 고려하여 적절한 도구를 선택하는 것이 중요하다.
댓글 0개
- 첫 댓글을 남겨보세요!