오늘은 react-navigation 오픈 소스를 사용하여 react-native에서의 화면 전환에 대해 알아보도록 해요.
우선 공식문서를 켜놓으시면 더 편하게 따라오실 수 있어요. 블로그 글도 간단하게 한글로 정리되서 좋지만 항상 공식문서를 읽는 습관을 들이는게 좋아요.
우선 프로젝트를 한 번 만들어보도록 하죠.
mac이면 터미널 window면 cmd를 켜서 react-native 프로젝트를 만들어주세요.
저는 navigation이라는 이름의 react-native 프로젝트를 한 번 만들어볼게요.
1# npx react-native init {프로젝트명}2npx react-native init navigation
공식문서에서 말하는대로 dependencies와 함께 react-navigation을 설치해볼게요.
1# cd {생성한 프로젝트명}2cd navigation34# react-navigation/native와 react-navigation/stack5# react-navigation/native의 dependencies인 react-native-screens, react-native-safe-area-context6# 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
ios는 방금 설치한 모듈들을 연결하기 위해 pod install을 진행해줘야 해요.
1cd ios2pod install3cd ..
android의 경우 android/app/src/main/java/<프로젝트명>/MainActivity.java
에서 아래의 코드를 추가해야해요.
아래 코드를 추가하지 않으면 앱을 백그라운드에서 포그라운드로 전환할 때 비정상 종료가 발생하는 경우가 생겨요.
1// android/app/src/main/java/<프로젝트명>/MainActivity.java23public class MainActivity extends ReactActivity {4 // ...5 @Override6 protected void onCreate(Bundle savedInstanceState) {7 super.onCreate(null);8 }9 // ...10}
@react-navigation/stack의 dependency인 react-native-gesture-handler를 index.js에서 import해줘요.
그렇지 않으면 빌드 중 오류가 발생하거나 화면 전환에 문제가 생길 수 있어요.
1// index.js23// ...4- import 'react-native-gesture-handler';5// ...
테스트 화면은 아래와 같이 구성할 예정이에요.
기존에 루트 디렉토리에 있던 App.tsx를 src/screens 폴더를 만든 후에 옮겨주세요.
마찬 가지로 src/screens 폴더 안에 Navigator.tsx, Screen1.tsx와 Screen2.tsx 파일을 만들어주세요.
그리고 Navigation의 type을 선언하기 위한 Navigation.ts 파일을 types 폴더를 만든 후에 만들어주세요.
1📦src2 ┣ 📂screens3 ┃ ┣ 📜App.tsx4 ┃ ┣ 📜Navigator.tsx5 ┃ ┣ 📜Screen1.tsx6 ┃ ┗ 📜Screen2.tsx7 ┗ 📂types8 ┃ ┗ 📜Navigation.ts
다른 코드들을 작성하기에 앞서 Naivgation에 어떤 스크린들이 존재하는지 타입을 지정해요.
우리는 Screen1과 Screen2만 존재하기 때문에 아래와 같이 타입을 설정해요.
Screen1: 과 Screen2: 의 undefined 값은 각 스크린들을 화면에 띄울 때 필요한 타입이 존재하지 않는다는 뜻이에요.
이에 관해서는 이어지는 포스팅에서 더 설명해보도록 하고 지금은 넘어가도록 할게요.
1// src/types/Navigation.ts23export type NaviParamList = {4 Screen1: undefined;5 Screen2: undefined;6};
크게 어려운 내용은 없지만 설명을 덧붙이자면 우리가 위의 3-1에서 선언해놨던 NaviParamList와 현재 스크린 명을 명시해서 NavigationProp을 선언해요.
그 후 useNavigation 훅을 통해 선언해놓은 NavigationProp 타입을 사용하는 navigation 변수를 생성해요.
Screen-2로 이동 버튼에 onPress event를 붙여서 Screen2로 이동하는 함수를 실행시켜요.
1// src/screens/Screen1.tsx23import { 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';89const 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});2324type NavigationProp = StackNavigationProp<NaviParamList, 'Screen1'>;2526export default function Screen1() {27 const navigation = useNavigation<NavigationProp>();2829 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}
위의 Screen1과 동일해요.
1// src/screens/Screen2.tsx23import { 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';89const 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});2324type NavigationProp = StackNavigationProp<NaviParamList, 'Screen2'>;2526export default function Screen2() {27 const navigation = useNavigation<NavigationProp>();2829 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}
이제 위에서 만든 Screen1과 Screen2를 연결할 네이게이터를 만들어 야겠죠?
우선 createStackNavigator를 사용해서 Stack 객체를 만들어줘요.
그 이후 아래의 코드와 같이 포함시키고 싶은 스크린들을 넣어줘요.
1// src/screens/Navigator.tsx23import React from 'react';4import { createStackNavigator } from '@react-navigation/stack';5import { NaviParamList } from '../types/Navigation';6import Screen1 from './Screen1';7import Screen2 from './Screen2';89const Stack = createStackNavigator<NaviParamList>();1011export 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}
이제 App.tsx의 기본 코드들을 모두 지운 후에 아래 코드와 같이 NavigationContainer로 위에서 만들어준 Navigator를 감싸줘요.
1// src/screens/App.tsx23import { NavigationContainer } from '@react-navigation/native';4import React from 'react';5import Navigator from './Navigator';67export default function App() {8 return (9 <NavigationContainer>10 <Navigator />11 </NavigationContainer>12 );13}
마지막으로 index.js의 App.tsx import 경로 를 수정해주면 끝이에요!
1// ...23- import App from './App';4+ import App from './src/screens/App';56// ...
이제 위에서 작성한 코드들이 잘 동작하는지 확인해요.
아마 잘 작동할텐데요.
react-native 0.7 버전 이후로 새로 만든 프로젝트가 실행 중 오류가 발생하는 경우가 있어요.
"launchPackager.command" can't be opened
라는 문구가 뜨면서 말이죠.
이런 경우 해결은 이 포스팅을 확인해주세요.
1# ios test2yarn ios34# android test5yarn android
https://github.com/classic-95/react-navigation-practice/tree/main/navigation-1
오늘은 react-navigation을 이용하여 화면을 전환하는 방법을 간단한 코드를 작성해서 알아봤어요.
다음 포스팅에서는 react-navigation의 navigate, push, replace 등의 화면 전환 함수들을 어떤 상황에 어떻게 사용해야 하는지에 대해 알아보도록 해요.