빠르게 내용을 흡수하기 위해, 스프링부트와 비교하며 해보자.
우선, npm과 Node.js를 필요로 하므로, 이 둘을 설치한 후 시작하자.
npx react-native init MyReactNativeApp
위 코드로 프로젝트를 만들 수 있다.
npm install -g react-native-cli
npx react-native run-android
위 코드로 프로젝트를 실행시킬 수 있다. 물론 안드로이드 스튜디오와 SDK 가 설정되어 있어야 한다.
@RestController
, @Service
, @Repository
등의 애노테이션을 사용하여 계층 구조를 나눈다.Component
가 스프링부트의 @RestController
와 유사하다.pom.xml
또는 build.gradle
을 통해 의존성을 관리한다.package.json
을 통해 의존성을 관리한다.다료구조:
위에 따라 코드를 만들어 보자.
// React 및 필요한 패키지 임포트
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
// 화면 컴포넌트 임포트
import PhotoList from './screens/PhotoList';
import UploadPhoto from './screens/UploadPhoto';
// Stack Navigator 생성
const Stack = createStackNavigator();
// 애플리케이션 컴포넌트 정의
function App() {
return (
// 네비게이션 컨테이너로 애플리케이션을 래핑
<NavigationContainer>
{/* Stack Navigator 설정 */}
<Stack.Navigator initialRouteName="PhotoList">
{/* 각 화면을 Stack Navigator에 추가 */}
<Stack.Screen name="PhotoList" component={PhotoList} />
<Stack.Screen name="UploadPhoto" component={UploadPhoto} />
</Stack.Navigator>
</NavigationContainer>
);
}
// App 컴포넌트 내보내기
export default App;
// 필요한 패키지 임포트
import React, { useState } from 'react';
import { View, Text, FlatList, Button, Image, StyleSheet } from 'react-native';
import { useNavigation } from '@react-navigation/native';
import * as FileSystem from 'expo-file-system';
import * as Sharing from 'expo-sharing';
import { photoData } from '../data/photoData';
// PhotoList 컴포넌트 정의
const PhotoList = () => {
// useState 훅으로 데이터 상태 관리
const [data, setData] = useState(photoData);
// 네비게이션 훅 사용
const navigation = useNavigation();
// 사진 다운로드 함수 정의
const downloadPhoto = async (uri, name) => {
// 파일 다운로드 경로 설정
const downloadPath = FileSystem.documentDirectory + name;
// 파일 다운로드
await FileSystem.downloadAsync(uri, downloadPath);
// 파일 공유
await Sharing.shareAsync(downloadPath);
};
return (
<View style={styles.container}>
{/* 리스트 렌더링 */}
<FlatList
data={data} // 리스트에 표시할 데이터
keyExtractor={(item) => item.id.toString()} // 각 항목의 고유 키 설정
renderItem={({ item }) => ( // 각 항목 렌더링
<View style={styles.item}>
{/* 이미지 표시 */}
<Image source= style={styles.image} />
<Text>{item.name}</Text>
{/* 다운로드 버튼 */}
<Button title="Download" onPress={() => downloadPhoto(item.uri, item.name)} />
</View>
)}
/>
{/* 사진 업로드 버튼 */}
<Button title="Upload Photo" onPress={() => navigation.navigate('UploadPhoto', { setData })} />
</View>
);
};
// 스타일 정의
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
item: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
padding: 10,
borderBottomWidth: 1,
},
image: {
width: 100,
height: 100,
marginRight: 10,
},
});
// PhotoList 컴포넌트 내보내기
export default PhotoList;
// 필요한 패키지 임포트
import React, { useState } from 'react';
import { View, Button, Image, StyleSheet } from 'react-native';
import * as ImagePicker from 'expo-image-picker';
import { useNavigation } from '@react-navigation/native';
// UploadPhoto 컴포넌트 정의
const UploadPhoto = ({ route }) => {
// 상태 관리
const [selectedImage, setSelectedImage] = useState(null);
const navigation = useNavigation();
const { setData } = route.params;
// 이미지 선택 함수 정의
const pickImage = async () => {
// 이미지 선택 권한 요청
let result = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (result.granted === false) {
alert("Permission to access media library is required!");
return;
}
// 이미지 선택
let pickerResult = await ImagePicker.launchImageLibraryAsync();
if (!pickerResult.canceled) {
setSelectedImage(pickerResult.assets[0]);
}
};
// 이미지 업로드 함수 정의
const uploadImage = () => {
if (selectedImage) {
setData(prevData => [
...prevData,
{ id: prevData.length + 1, uri: selectedImage.uri, name: selectedImage.fileName || `photo${prevData.length + 1}.jpg` }
]);
navigation.goBack();
}
};
return (
<View style={styles.container}>
{/* 이미지 선택 버튼 */}
<Button title="Pick an image" onPress={pickImage} />
{selectedImage && <Image source= style={styles.image} />}
{/* 업로드 버튼 */}
<Button title="Upload" onPress={uploadImage} disabled={!selectedImage} />
</View>
);
};
// 스타일 정의
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
image: {
width: 200,
height: 200,
marginVertical: 20,
},
});
// UploadPhoto 컴포넌트 내보내기
export default UploadPhoto;
data/photoData.js
// 초기 사진 데이터 정의
export const photoData = [];
위 코드를 활용하면 사진을 업로드, 다운로드 할 수 있는 앱을 만들수 있다.
하지만, 위의 코드를 통해서 만든 App 에는 저런 파일들이 없을 뿐더라 그런 구조도 아니다.
따라서, 필요한 파일과 폴더를 직접 생성하여 기존 프로젝트에 추가하면 된다.
MyReactNativeApp/
|-- android/
|-- ios/
|-- node_modules/
|-- src/
| |-- screens/
| | |-- PhotoList.js
| | |-- UploadPhoto.js
| |-- data/
| | |-- photoData.js
|-- App.tsx
|-- package.json
|-- ...
src 폴더를 하나 만들고 그 안에 저 파일들을 직접 만들면 된다.
App.js는 이미 App.tsx가 잇으므로, 그 파일을 수정하자.
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import PhotoList from './src/screens/PhotoList';
import UploadPhoto from './src/screens/UploadPhoto';
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="PhotoList">
<Stack.Screen name="PhotoList" component={PhotoList} />
<Stack.Screen name="UploadPhoto" component={UploadPhoto} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
이어서, Expo를 설정하자.
Expo는 리액트 네이티브보다 더 간단하며, 웹뷰 앱 같은거 만들기 참 쉬운 맵이다.
아쉽게도, 지금 내 환경은 안드로이드스튜디오를 작동할 수 없기에 이런 방법을 사용하는 것이다.
npm을 사용하기 위해선 다음을 설치해야 한다.
https://nodejs.org/en
Expo CLI를 설치하자.
npm install -g expo-cli
기존 React Native 프로젝트를 Expo 프로젝트로 변환하자.
expo init MyExpoApp
cd MyExpoApp
새로 생성된 Expo 프로젝트에 기존 React Native 프로젝트의 src 폴더와 App.tsx 파일을 옮기자
cp -r ../MyReactNativeApp/src ./src
cp ../MyReactNativeApp/App.tsx ./App.tsx
필요한 종속성이 남아있다.
cd MyExpoApp
expo install @react-navigation/native @react-navigation/stack react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view expo-image-picker expo-file-system expo-sharing
위 코드를 통해서 작동하자.
expo start
이 코드는 QR 코드를 포함한 로컬 서버 URL을 출력한다.
Expo Go 앱을 다운받아서 QR 코들르 스캔하면 실행할 수 있다.
또한,
expo build:android
expo build:ios
이 코드를 통해서 APK 파일을 만들고, 이를 안드로이드에서 설치할 수 있다.
위 과정에서 종속성 버젼 오류가 나온다. 이를 해결하면, 앱을 실행할 수 있을 것이다.