Gihak111 Navbar

전에 했엇던 스프링부트와 비교하자

빠르게 내용을 흡수하기 위해, 스프링부트와 비교하며 해보자.
우선, npm과 Node.js를 필요로 하므로, 이 둘을 설치한 후 시작하자.

npx react-native init MyReactNativeApp

위 코드로 프로젝트를 만들 수 있다.

npm install -g react-native-cli
npx react-native run-android

위 코드로 프로젝트를 실행시킬 수 있다. 물론 안드로이드 스튜디오와 SDK 가 설정되어 있어야 한다.

스프링부트와 리액트 네이티브의 비교

리액트 네이티브 예제 만들기

다료구조:

위에 따라 코드를 만들어 보자.

App.js

// 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;

screens/PhotoList.js

// 필요한 패키지 임포트
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;

screens/UploadPhoto.js

// 필요한 패키지 임포트
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 파일을 만들고, 이를 안드로이드에서 설치할 수 있다.

위 과정에서 종속성 버젼 오류가 나온다. 이를 해결하면, 앱을 실행할 수 있을 것이다.