[react-native] react-navigation으로 화면 전환 시작하기

오늘은 react-navigation 오픈 소스를 사용하여 react-native에서의 화면 전환에 대해 알아보도록 해요.

우선 공식문서를 켜놓으시면 더 편하게 따라오실 수 있어요. 블로그 글도 간단하게 한글로 정리되서 좋지만 항상 공식문서를 읽는 습관을 들이는게 좋아요.


1. 프로젝트 만들기

우선 프로젝트를 한 번 만들어보도록 하죠.

mac이면 터미널 window면 cmd를 켜서 react-native 프로젝트를 만들어주세요.

저는 navigation이라는 이름의 react-native 프로젝트를 한 번 만들어볼게요.

1# npx react-native init {프로젝트명}
2npx react-native init navigation

2. react-navigation 설치

공식문서에서 말하는대로 dependencies와 함께 react-navigation을 설치해볼게요.

1# cd {생성한 프로젝트명}
2cd navigation
3
4# react-navigation/native와 react-navigation/stack
5# react-navigation/native의 dependencies인 react-native-screens, react-native-safe-area-context
6# react-navigation/stack의 dependency인 react-native-gesture-handler 를 함께 설치
7yarn add @react-navigation/native @react-navigation/stack react-native-screens react-native-safe-area-context react-native-gesture-handler

2-1. ios 추가 작업

ios는 방금 설치한 모듈들을 연결하기 위해 pod install을 진행해줘야 해요.

1cd ios
2pod install
3cd ..

2-2. android 추가 작업

android의 경우 android/app/src/main/java/<프로젝트명>/MainActivity.java 에서 아래의 코드를 추가해야해요.

아래 코드를 추가하지 않으면 앱을 백그라운드에서 포그라운드로 전환할 때 비정상 종료가 발생하는 경우가 생겨요.

1// android/app/src/main/java/<프로젝트명>/MainActivity.java
2
3public class MainActivity extends ReactActivity {
4 // ...
5 @Override
6 protected void onCreate(Bundle savedInstanceState) {
7 super.onCreate(null);
8 }
9 // ...
10}

2-3. ios, android 공통 작업

@react-navigation/stack의 dependency인 react-native-gesture-handler를 index.js에서 import해줘요.

그렇지 않으면 빌드 중 오류가 발생하거나 화면 전환에 문제가 생길 수 있어요.

1// index.js
2
3// ...
4- import 'react-native-gesture-handler';
5// ...

3. 테스트 화면 작성

테스트 화면은 아래와 같이 구성할 예정이에요.

기존에 루트 디렉토리에 있던 App.tsx를 src/screens 폴더를 만든 후에 옮겨주세요.

마찬 가지로 src/screens 폴더 안에 Navigator.tsx, Screen1.tsx와 Screen2.tsx 파일을 만들어주세요.

그리고 Navigation의 type을 선언하기 위한 Navigation.ts 파일을 types 폴더를 만든 후에 만들어주세요.

1📦src
2 ┣ 📂screens
3 ┃ ┣ 📜App.tsx
4 ┃ ┣ 📜Navigator.tsx
5 ┃ ┣ 📜Screen1.tsx
6 ┃ ┗ 📜Screen2.tsx
7 ┗ 📂types
8 ┃ ┗ 📜Navigation.ts

3-1. Navigation.ts 타입 코드 작성

다른 코드들을 작성하기에 앞서 Naivgation에 어떤 스크린들이 존재하는지 타입을 지정해요.

우리는 Screen1과 Screen2만 존재하기 때문에 아래와 같이 타입을 설정해요.

Screen1: 과 Screen2: 의 undefined 값은 각 스크린들을 화면에 띄울 때 필요한 타입이 존재하지 않는다는 뜻이에요.

이에 관해서는 이어지는 포스팅에서 더 설명해보도록 하고 지금은 넘어가도록 할게요.

1// src/types/Navigation.ts
2
3export type NaviParamList = {
4 Screen1: undefined;
5 Screen2: undefined;
6};

3-2. Screen1.tsx 코드 작성

크게 어려운 내용은 없지만 설명을 덧붙이자면 우리가 위의 3-1에서 선언해놨던 NaviParamList와 현재 스크린 명을 명시해서 NavigationProp을 선언해요.

그 후 useNavigation 훅을 통해 선언해놓은 NavigationProp 타입을 사용하는 navigation 변수를 생성해요.

Screen-2로 이동 버튼에 onPress event를 붙여서 Screen2로 이동하는 함수를 실행시켜요.

react-native navigation screen1
1// src/screens/Screen1.tsx
2
3import { StackNavigationProp } from '@react-navigation/stack';
4import React from 'react';
5import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
6import { NaviParamList } from '../types/Navigation';
7import { useNavigation } from '@react-navigation/native';
8
9const styles = StyleSheet.create({
10 container: {
11 flex: 1,
12 alignItems: 'center',
13 justifyContent: 'center',
14 },
15 button: {
16 padding: 10,
17 backgroundColor: 'black',
18 },
19 buttonLabel: {
20 color: 'white',
21 },
22});
23
24type NavigationProp = StackNavigationProp<NaviParamList, 'Screen1'>;
25
26export default function Screen1() {
27 const navigation = useNavigation<NavigationProp>();
28
29 return (
30 <View style={styles.container}>
31 <TouchableOpacity style={styles.button} onPress={() => navigation.navigate('Screen2')}>
32 <Text style={styles.buttonLabel}>Screen-2로 이동</Text>
33 </TouchableOpacity>
34 </View>
35 );
36}

3-3. Screen2.tsx 코드 작성

위의 Screen1과 동일해요.

react-native navigation screen2
1// src/screens/Screen2.tsx
2
3import { StackNavigationProp } from '@react-navigation/stack';
4import React from 'react';
5import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
6import { NaviParamList } from '../types/Navigation';
7import { useNavigation } from '@react-navigation/native';
8
9const styles = StyleSheet.create({
10 container: {
11 flex: 1,
12 alignItems: 'center',
13 justifyContent: 'center',
14 },
15 button: {
16 padding: 10,
17 backgroundColor: 'black',
18 },
19 buttonLabel: {
20 color: 'white',
21 },
22});
23
24type NavigationProp = StackNavigationProp<NaviParamList, 'Screen2'>;
25
26export default function Screen2() {
27 const navigation = useNavigation<NavigationProp>();
28
29 return (
30 <View style={styles.container}>
31 <TouchableOpacity style={styles.button} onPress={() => navigation.navigate('Screen1')}>
32 <Text style={styles.buttonLabel}>Screen-1로 이동</Text>
33 </TouchableOpacity>
34 </View>
35 );
36}

3-4. Navigator.tsx 코드 작성

이제 위에서 만든 Screen1과 Screen2를 연결할 네이게이터를 만들어야겠죠?

우선 createStackNavigator를 사용해서 Stack 객체를 만들어줘요.

그 이후 아래의 코드와 같이 포함시키고 싶은 스크린들을 넣어줘요.

1// src/screens/Navigator.tsx
2
3import React from 'react';
4import { createStackNavigator } from '@react-navigation/stack';
5import { NaviParamList } from '../types/Navigation';
6import Screen1 from './Screen1';
7import Screen2 from './Screen2';
8
9const Stack = createStackNavigator<NaviParamList>();
10
11export default function Navigator() {
12 return (
13 <Stack.Navigator>
14 <Stack.Screen name="Screen1" component={Screen1} />
15 <Stack.Screen name="Screen2" component={Screen2} />
16 </Stack.Navigator>
17 );
18}

3-5. App.tsx 코드 수정

이제 App.tsx의 기본 코드들을 모두 지운 후에 아래 코드와 같이 NavigationContainer로 위에서 만들어준 Navigator를 감싸줘요.

1// src/screens/App.tsx
2
3import { NavigationContainer } from '@react-navigation/native';
4import React from 'react';
5import Navigator from './Navigator';
6
7export default function App() {
8 return (
9 <NavigationContainer>
10 <Navigator />
11 </NavigationContainer>
12 );
13}

3-6. index.js 코드 수정

마지막으로 index.js의 App.tsx import 경로를 수정해주면 끝이에요!

1// ...
2
3- import App from './App';
4+ import App from './src/screens/App';
5
6// ...

4. 실행

이제 위에서 작성한 코드들이 잘 동작하는지 확인해요.

아마 잘 작동할텐데요.

react-native 0.7 버전 이후로 새로 만든 프로젝트가 실행 중 오류가 발생하는 경우가 있어요.

"launchPackager.command" can't be opened 라는 문구가 뜨면서 말이죠.

이런 경우 해결은 이 포스팅을 확인해주세요.

1# ios test
2yarn ios
3
4# android test
5yarn android

전체 코드

https://github.com/classic-95/react-navigation-practice/tree/main/navigation-1


정리하며

오늘은 react-navigation을 이용하여 화면을 전환하는 방법을 간단한 코드를 작성해서 알아봤어요.

다음 포스팅에서는 react-navigation의 navigate, push, replace 등의 화면 전환 함수들을 어떤 상황에 어떻게 사용해야 하는지에 대해 알아보도록 해요.