React Native에서 네비게이션을 이야기할 때 가장 먼저 떠오르는 라이브러리가 바로 react-navigation입니다.
저는 이 라이브러리의 열렬한 팬으로, React Native에서 네비게이션을 처리할 때 항상 첫 번째 선택지로 삼습니다. 훌륭하고 사용하기 쉬운 API를 갖추고 있을 뿐만 아니라 커스터마이징 자유도가 매우 높기 때문입니다.
이 글을 쓰게 된 이유는 버전 5가 드디어 베타 단계를 거쳐 정식(stable) 버전으로 출시되었기 때문입니다. 여러 기능 변화와 함께 라우트를 선언하는 더 간단하고 색다른 방식의 새로운 API 디자인이 도입되었습니다.
이번 글에서는 새롭게 바뀐 API들을 하나씩 살펴보고, 실제 애플리케이션에서 활용하는 방법까지 알아보겠습니다.
설치 방법
react-navigation의 설치 방식은 이전 버전(4.x 이하)과 비교해 조금 달라졌습니다.
// 4.x 이하 버전
yarn add react-navigation
react-navigation 5의 설치는 다음과 같습니다.
// yarn
yarn add @react-navigation/native
// npm
npm install @react-navigation/native
최신 버전의 react-navigation은 애니메이션과 화면 전환 처리를 위해 react-native-gesture-handler와 같은 서드파티 라이브러리를 폭넓게 활용합니다. 따라서 아래 라이브러리들도 반드시 함께 설치해야 합니다.
// yarn
yarn add react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view
// npm
npm install react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view
동적 스크린(Dynamic Screens)
새로운 API는 라우트 초기화 과정에 '동적' 요소를 도입했습니다. 이전에는 정적(static) 방식으로, 설정 파일 안에 라우트를 미리 정의해 두어야 했습니다.
// @flow
import React from "react";
import { createAppContainer, createSwitchNavigator } from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";
/** ---------Screens----------- */
import HomeScreen from "../Containers/HomeScreen";
import ProfileScreen from "../Containers/ProfileScreen";
import LoginScreen from "../Containers/LoginScreen";
const StackNavigator = createStackNavigator(
{
initialRouteName: "Home"
},
{
Home: {
screen: HomeScreen
},
Login: {
screen: LoginScreen,
headerMode: "none",
},
Profile: {
screen: ProfileScreen
}
}
);
export default createAppContainer(StackNavigator);
반면 새로운 API는 동적 컴포넌트 방식을 제공하여 네비게이션을 훨씬 더 유연하게 구성할 수 있습니다.
새로운 방식으로 라우트를 선언하면 아래와 같이 작성하게 됩니다.
import React from "react"
import { SafeAreaView, StyleSheet, View, Text, StatusBar } from "react-native"
import { NavigationContainer } from "@react-navigation/native"
import { createStackNavigator } from "@react-navigation/stack"
const App: () => React$Node = () => {
return (
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView style={styles.containerStyle}>
<AppNavigation />
</SafeAreaView>
</>
)
}
const Stack = createStackNavigator()
const AppNavigation = () => {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="home">
<Stack.Screen name="home" component={HomeScreen} />
</Stack.Navigator>
</NavigationContainer>
)
}
const HomeScreen = () => {
return (
<View style={styles.containerStyle}>
<Text style={styles.title}>Home Screen</Text>
</View>
)
}

이 새로운 방식은 동적이면서도 사용법이 훨씬 간단하고, 어딘가 react-router의 API와 비슷한 느낌마저 줍니다.
동적 옵션(Dynamic Options)
이 기능은 오랫동안 커뮤니티에서 가장 많이 요청받던 기능입니다. 저 역시 기존의 정적 방식 때문에 늘 불편함을 겪었고, 네비게이션 동작을 동적으로 변경하는 일이 무척 까다로웠습니다.
기존 방식 (4.x 이하)
구버전의 react-navigation에서는 옵션을 정적으로 정의해야 했고, 이를 런타임에 동적으로 변경할 방법이 없었습니다.
static navigationOptions = {
title: "Sign In",
header: null,
mode: "modal",
headerMode: "none"
};
새로운 방식 (버전 5)
react-navigation 5는 무척 간단한 동적 방식을 제공합니다. 이제 props만으로 어떤 화면에든 옵션을 자유롭게 지정할 수 있습니다.
const AppNavigation = ({}) => {
let auth = {
authenticated: true,
user: {
email: "user@mail.com",
username: "John",
},
}
let ProfileScreenTitle = auth.authenticated ? auth.user.username : "Profile"
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen
name="Profile"
component={ProfileScreen}
options={{
title: ProfileScreenTitle,
headerTintColor: "#4aa3ba",
headerStyle: {
backgroundColor: darkModeOn ? "#000" : "#fff",
},
}}
/>
<Stack.Screen name="About" component={AboutScreen} />
</Stack.Navigator>
</NavigationContainer>
)
}

동적 옵션을 활용하면 인증 상태에 따라 화면 제목을 바꿀 수 있습니다. 예를 들어 사용자가 로그인한 상태라면 화면 제목을 해당 사용자의 닉네임으로 설정하거나, 헤더의 배경색을 상황에 맞게 변경할 수도 있습니다.
이 기능은 특히 동적으로 테마를 교체하거나 앱에 다크 모드를 구현하려는 경우에 매우 유용합니다.
훅(Hooks)
개인적으로 가장 마음에 드는 기능이며, 개발 시간을 크게 절약해 줍니다. 새로운 API는 특정 동작을 손쉽게 수행할 수 있는 커스텀 훅들을 도입했습니다.
이전 버전에서는, 예를 들어 현재 활성화된 화면의 이름(routeName)을 가져오려면 다음과 같은 헬퍼 함수를 직접 만들어야 했습니다.
export function getCurrentRouteName(): string | null {
const tag = "[getCurrentRouteNameSync] "
const navState = getStore().getState().nav
const currentRoute = getActiveRouteState(navState)
console.log(tag + " currentRoute > ", currentRoute)
return currentRoute && currentRoute.routeName ? currentRoute.routeName : null
}
훅(Hooks) API는 이런 번거로운 작업을 없애 주고, 단 한 줄의 훅으로 네비게이션 API에 접근할 수 있게 해 줍니다.
이제 useRoute 훅으로 RouteName을 간편하게 가져올 수 있습니다.
import { useRoute } from "@react-navigation/native"
const AboutScreen = ({ navigation }) => {
const route = useRoute()
return (
<View
style={{
justifyContent: "space-around",
flex: 1,
alignItems: "center",
}}
>
{/* 여기서 RouteName을 표시합니다 */}
<Text style={styles.title}>{route.name}</Text>
</View>
)
}
useNavigationState 훅으로도 같은 작업이 가능합니다. 이 훅은 네비게이션 상태 전체에 접근할 수 있게 해 줍니다.
const navigationState = useNavigationState(state => state)
let index = navigationState.index
let routes = navigationState.routes.length
console.log(index)
console.log(routes)
react-navigation은 그 외에도 다양한 훅을 제공합니다. 대표적인 예는 다음과 같습니다.
useFocusEffect: 화면이 로드되어 포커스될 때 부수 효과(side effect)를 실행하는 훅useLinking: 딥링킹(deep linking)을 처리하는 훅
이 훅들은 공식 문서를 통해 직접 확인해 보시길 강력히 추천합니다.
마치며
새로운 react-navigation API는 분명히 정적 방식에서 동적 방식으로 전환하고 있습니다. React Native에서 네비게이션을 다루는 방식을 완전히 바꿀 수 있는 훌륭한 방향입니다. 동적 라우트는 react-navigation 사용자들이 오랫동안 요청해 온 기능이었고, 이 새로운 방식은 더 나은 사용자 네비게이션 경험을 만드는 데 큰 도움이 될 것입니다.
읽어주셔서 감사합니다. 원문은 saidhayani.com에 게시되었습니다.