React-native(with. Expo Cli)

🌐리액트 네이티브 시작하기(with. Expo Cli)

minnote29 2025. 4. 21. 20:48
더보기

🍎 리액트 네이티브 공식문서 참고.

리액트 네이티브를 사용하면 리액트를 아는 개발자도 네이티브 앱을 만들 수 있다. 프레임워크 없이 리액트 네이티브를 사용할 수도 있지만, 대부분의 개발자는 expo와 같은 리액트 네이티브 프레임워크를 사용하는 것이 유리하다는 것을 알 수 있다. expo는 파일 기반 라우팅, 고품질 범용 라이브러리, 그리고 네이티브 파일을 관리하지 않고도 네이티브 코드를 수정하는 플러그인을 작성할 수 있는 기능 등의 기능을 제공한다.

React Native는 프레임워크 없이도 사용할 수 있다. 하지만 새로운 앱을 React Native로 개발하려는 경우, 프레임워크를 사용하는 것을 추천한다고 한다. 간단히 말해, 프레임워크를 사용하면 앱 자체를 개발하는 데 집중할 수 있으며, 앱과 별도로 프레임워크 전체를 직접 만들 필요가 없어진다는 것이다. React Native 커뮤니티는 수년 동안 내비게이션, 네이티브 API 접근, 네이티브 의존성 처리 등 다양한 문제에 대한 접근 방식을 다듬어 왔는데, 대부분의 앱은 이러한 핵심 기능들이 필요하다. React Native 프레임워크는 이런 기능들을 앱을 처음 만들 때부터 바로 제공한다. 프레임워크 없이 개발하면, 이러한 핵심 기능들을 직접 구현하거나, 기존에 있는 여러 라이브러리들을 모아 일종의 프레임워크 뼈대를 직접 구성해야 한다. 이 과정은 앱을 시작할 때뿐만 아니라, 이후 유지보수 시에도 꽤 많은 작업을 요구한다. 만약 앱이 프레임워크로는 잘 해결되지 않는 특수한 제약사항이 있거나, 이러한 문제들을 직접 해결하고 싶다면, Android Studio나 Xcode를 사용하여 프레임워크 없이 React Native 앱을 만들 수도 있다. 이 방법에 관심이 있다면, 개발 환경 설정 방법과 프레임워크 없이 시작하는 절차를 먼저 익히는 것이 좋다.

 

 

 

📁 Expo로 리액트 네이티브 프로젝트 시작하기

지원 플랫폼 

 

  • Android
  • iOS
  • TV
  • Web

리액트 네이티브 공식문서를 통해 말하자면, Expo는 프로덕션 수준의 리액트 네이티브 프레임워크이다. Expo는 파일 기반 라우팅, 표준 네이티브 모듈 라이브러리 등 앱 개발을 더 쉽게 만들어주는 다양한 개발 도구를 제공한다. 

Expo의 프레임워크는 무료이며 오픈 소스로, GitHub 및 Discord에서 활발한 커뮤니티가 운영되고 있다. 또한 Expo 팀은 Meta(구 Facebook)의 React Native 팀과 긴밀히 협력하여 최신 React Native 기능들을 Expo SDK에 빠르게 통합하고 있다. Expo 팀은 Expo Application Services (EAS)도 제공하고 있다. EAS는 Expo 프레임워크를 보완해주는 선택적 서비스 세트로, 개발의 모든 단계에서 활용될 수 있다.

새로운 Expo 프로젝트를 생성하기 위해서 터미널에 아래처럼 명령어를 입력해준다. 

$ npx create-expo-app@latest

앱 이름은 friction-break로 생성해줬다.

앱 생성 후, 핸드폰에서 Expo go를 다운받아 준다. 개발은 Android device로 할 예정이다. 

프로젝트와 개발 환경이 준비되면 다음 단계로 넘어간다. 

개발 서버 시작을 위해 아래 명령어를 입력해준다.

$ cd friction-break
$ npx expo start

위 명령을 실행하면 터미널에 qr 코드가 표시된다. 이 qr 코드를 스캔하여 기기에서 앱을 열어볼 수 있다. 안드 에뮬 또는 ios 시뮬로 사용하는 경우 각각 a 또는 i를 눌러 앱을 열 수 있다. 

실행이 되지 않는 다면 라우터 설정 문제일 수도 있다. 이는 공용 네트워크에서 흔히 발생하는 문제이다. 개발 서버를 시작할 때 터널 연결 유형을 선택한 후 qr 코드를 다시 스캔하면 이 문제를 해결할 수 있다. 

$ npx expo start --tunnel
더보기

터널 연결 유형을 사용하면 lan이나 로컬 연결보다 앱 재로드 속도가 상당히 느려지므로 가능하면 터널 연결은 피하는 것이 좋다. 네트워크의 다른 기기에서 터널을 통해 기기에 접속해야 하는 경우, 개발 속도를 높이기 위해 에뮬레이터나 시뮬레이터를 설치하여 사용하는 것이 좋다. 

그 다음, 코드 편집기에서 app/(tabs)/index.tsx 파일을 열고 변경한다.

위 사진에서 19줄은 없애고 저장해보면 핸드폰에 즉각적으로 업데이트되는 것을 알 수 있다. 변경해봤으면 다시 되돌려준다. 

Expo Go는 기본적으로 파일이 변경될 때마다 앱을 자동으로 다시 로드하도록 구성되어 있지만, 어떻게든 작동하지 않을 경우를 대비해 이를 활성화하는 단계를 살펴봐야 한다.

  • Expo CLI에서 개발 모드가 활성화되어 있는지 확인하고,
  • Expo 앱을 닫았다가 다시 열어본다.
  • 앱을 다시 열면 기기를 흔들어 개발자 메뉴를 열고, 에뮬레이터를 사용하는 경우 Android는 Ctrl + M , iOS는 Cmd ⌘ + D 를 누른다. 
  • 빠른 새로 고침 사용 설정이 표시되면 누르고, 빠른 새로 고침 사용 안 함 설정이 표시되면 개발자 메뉴를 닫는다. 이제 다른 설정을 변경해 본다.
  • 기본 파일 구조는 아래와 같을 것이다. 

 

 

 

 

 

📁 파일 기반 라우팅 - Expo Router

Expo Router는 React Native 및 웹 애플리케이션을 위한 라우팅 프레임워크이다. 앱 내 화면 간 탐색을 관리하고 여러 플랫폼(Android, iOS 및 웹)에서 동일한 컴포넌트를 사용할 수 있도록 지원한다. 파일 기반 방식을 사용하여 앱 내 경로를 결정한다. 또한 React Navigation을 기반으로 네이티브 탐색 기능을 제공한다.

app 특수 디렉터리이다. 이 디렉터리에 추가하는 모든 파일은 네이티브 앱 내부의 경로가 되며, 웹에서도 해당 경로의 URL과 동일하게 반영된다.

app 디렉토리에서 index.tsx 파일을 포함하는 파일이나 중첩 디렉토리를 추가하여 경로를 생성한다. 예를 들어, 앱의 초기 경로를 만들려면 다음 코드를 사용하여 index.tsx를  디렉터리 에 추가할 수 있다.

import { View, Text, StyleSheet } from 'react-native';

export default function HomeScreen() {
  return (
    <View style={styles.container}>
      <Text>Home</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

app/index.tsx

  • 파일 이름 규칙
  • index 라는 이름의 파일은 상위 디렉터리와 일치하며 경로 세그먼트를 추가하지 않는다. 예를 들어, app/settings/index.tsx를 추가하여 앱의 파일 구조를 확장하면 경로와 일치하게 된다. /settings.

경로 파일은 React 컴포넌트를 기본값으로 내보내 정의된다. 경로 파일은 
.js, .jsx, .ts, 또는 .tsx 확장자를 사용해야 한다.

 

_layout 파일 - 디렉토리의 layout 파일은 헤더, 탭 바와 같은 공유 ui 요소를 정의하여 서로 다른 경로 간에 유지되도록 하는 데 사용된다. 새로운 프로젝트를 생성할 때마다 기본적으로 app 디렉토리에 root layout 파일(app/_layout)이 포함된다. 

root layout - 전통적으로 React Native 프로젝트는 단일 루트 컴포넌트( App.js 또는 index.js 로 정의됨)로 구성된다. 마찬가지로, app 디렉터리 내의 첫 번째 레이아웃 파일( _layout.tsx ) 이 단일 루트 컴포넌트로 간주된다. 여러 경로 사이에서 Expo Router의 루트 레이아웃 파일은 글로벌 공급자, 테마, 스타일을 주입하거나, 자산과 글꼴이 로드될 때까지 시작 화면 렌더링을 지연하거나, 앱의 루트 탐색 구조를 정의하는 등 여러 경로 간에 UI를 공유하는 데 사용된다.

Expo Router를 사용하면 app/_layout.tsx 에 정의된 모든 React provider들은 앱의 모든 경로에서 접근할 수 있다. 성능을 향상시키고 렌더링 횟수를 줄이려면 프로바이더의 범위를 해당 프로바이더가 필요한 경로로만 제한하는 것이 좋다.

 

 

 

📁 Stack Navigator

Stack Navigator는 앱에서 서로 다른 라우트 간을 이동하기 위한 패턴이다. 이 패턴은 화면 간 전환과 내비게이션 기록 관리를 가능하게 해준다.
개념적으로는 웹 브라우저가 내비게이션 상태를 관리하는 방식과 유사하다. 예를 들어, 새로운 라우트 /details를 추가하고 싶다면 details.tsx 파일을 생성하면 된다. 이렇게 하면 사용자가 / 라우트에서 /details 라우트로 이동할 수 있다.

import { View, Text, StyleSheet } from 'react-native';

export default function DetailsScreen() {
  return (
    <View style={styles.container}>
      <Text>Details</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

app/detaills.tsx

위 사진처럼 구조가 생성될 것이다. 

root layout을 수정해서, /와 /details 두 라우트 간의 내비게이션을 허용하려면, root layout 파일을 업데이트하고 stack 컴포넌트를 추가해야 한다. 

import { Stack } from 'expo-router';

export default function RootLayout() {
  return (
    <Stack
      screenOptions={{
        headerStyle: {
          backgroundColor: '#f4511e',
        },
        headerTintColor: '#fff',
        headerTitleStyle: {
          fontWeight: 'bold',
        },
      }}>
      <Stack.Screen name="index" />
      <Stack.Screen name="details" />
    </Stack>
  );
}

app/_layout.tsx

<Stack.Screen name={routeName} /> 컴포넌트는 레이아웃 파일 내에서 Stack에 라우트를 정의할 수 있게 해준다.

참고: 위 예시의 screenOptions는 스택 내 모든 라우트에 대한 설정을 구성할 수 있게 해줍니다. 자세한 정보는 Statically configure route options를 참고하면 된다.

https://docs.expo.dev/router/advanced/stack/#statically-configure-route-options

 

Stack

Learn how to use the Stack navigator in Expo Router.

docs.expo.dev

 

 

 

📁 라우트 간 내비게이션

Expo Router는 앱 내 라우트 간 이동을 위해 Link라는 내장 컴포넌트를 사용한다. 이는 개념적으로 웹의 <a> 태그와 href 속성과 유사하게 작동합니다. expo-router 라이브러리에서 Link를 가져와 사용하고, href 속성에 이동하고 싶은 라우트를 설정하면 된다. 예를 들어, /에서 /details로 이동하고 싶다면 index.tsx에 Link 컴포넌트를 추가하면 된다.

import { Link } from 'expo-router';
import { View, Text, StyleSheet } from 'react-native';

export default function HomeScreen() {
  return (
    <View style={styles.container}>
      <Text>Home</Text>
      <Link href="/details">View details</Link>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

app/index.tsx

Link는 어떻게 작동하냐면 Link는 기본적으로 자식 요소를 <Text>로 감싼다. 하지만 다른 버튼 컴포넌트를 사용하고 싶다면 커스터마이징이 가능하다. 사용자 정의 버튼 컴포넌트를 Link로 감싸고, asChild 속성을 사용하면 Link의 모든 props가 첫 번째 자식 컴포넌트로 전달된다. Link 컴포넌트의 props에 대한 더 자세한 정보는 Navigate between pages 문서를 참고하면 된다.

https://docs.expo.dev/router/basics/navigation/

 

Navigating between pages

Learn the different ways to link to and navigate to pages in Expo Router.

docs.expo.dev

 

 

 

📁 Groups (그룹)

그룹(Group)은 비슷한 라우트나 앱의 섹션을 정리하기 위해 사용된다.
각 그룹은 고유한 레이아웃 파일을 가지며, 그룹 디렉터리는 괄호로 감싼 이름을 가져야 한다. 예: (home)

예시: / 와 /details 라우트를 (home) 그룹에 넣기 -> 디렉토리 구조는 다음과 같이 변경된다:

→ app/(home)/_layout.tsx 파일을 추가하여 / 및 /details 라우트에 대한 Stack Navigator를 정의해야 한다.

import { Stack } from 'expo-router';

export default function HomeLayout() {
  return (
    <Stack
      screenOptions={{
        headerStyle: {
          backgroundColor: '#f4511e',
        },
        headerTintColor: '#fff',
        headerTitleStyle: {
          fontWeight: 'bold',
        },
      }}>
      <Stack.Screen name="index" />
      <Stack.Screen name="details" />
    </Stack>
  );
}

app/(home)/_layout.tsx

이제 루트 레이아웃에서도 (home) 그룹을 포함해야 하며, 앱의 초기 라우트는 (home)/index가 된다.

import { Stack } from 'expo-router';

export default function RootLayout() {
  return (
    <Stack>
      <Stack.Screen name="(home)" />
    </Stack>
  );
}

app/_layout.tsx

주의: 위 예시에서 screenOptions는 (home)/_layout.tsx로 이동했다. 따라서 루트 레이아웃에서 Stack Navigator에 라우트를 추가하더라도, (home) 내부 라우트처럼 동일한 옵션이 적용되지 않는다.

 

 

 

📁 Tab Navigator

Tab Navigator는 앱의 다양한 섹션 간을 탭 바를 통해 이동할 수 있게 해주는 일반적인 패턴이다. Expo Router는 Tabs라는 내비게이션 컴포넌트를 제공한다.

예시: 홈(/, /details)과 설정(/settings) 탭 구성 - (tabs)라는 특수 디렉터리를 생성하고 기존 홈 라우트 파일들을 이 안으로 옮기고 settings.tsx를 생성한다:

→ (tabs) 디렉터리 내부의 모든 파일 및 디렉터리는 탭 내비게이터의 하나의 라우트가 된다.

import { Tabs } from 'expo-router';

export default function TabLayout() {
  return (
    <Tabs>
      <Tabs.Screen name="(home)" />
      <Tabs.Screen name="settings" />
    </Tabs>
  );
}

app/(tabs)/_layout.tsx

주의: (home)에 대한 기존 Stack Navigator는 이제 탭 내에 중첩(nested)되어 있다.

app/_layout.tsx 업데이트 - 탭 내비게이션을 활성화하려면 루트 레이아웃에서 (tabs)를 최상위 라우트로 추가해야 한다.

import { Stack } from 'expo-router';

export default function RootLayout() {
  return (
    <Stack>
      <Stack.Screen name="(tabs)" />
    </Stack>
  );
}

app/_layout.tsx

 

 

 

📁 Not Found Routes (404 처리)

Expo Router는 +not-found.tsx라는 특수 파일을 제공하여 정의되지 않은(404) 라우트를 처리할 수 있다. 이 파일은 중첩 레벨에서도 모든 매치되지 않는 라우트를 감지한다.

import { Link, Stack } from 'expo-router';
import { View, StyleSheet } from 'react-native';

export default function NotFoundScreen() {
  return (
    <>
      <Stack.Screen options={{ title: "Oops! This screen doesn't exist." }} />
      <View style={styles.container}>
        <Link href="/">Go to home screen</Link>
      </View>
    </>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

app/+not-found.tsx

이 화면은 유효하지 않은 라우트에 접근했을 때 표시되는 404 페이지 역할을 한다. 홈으로 돌아갈 수 있는 링크도 함께 포함되어 있다.