React Native에서 네비게이션을 이야기할 때 가장 먼저 떠오르는 라이브러리가 바로 react-navigation입니다.
저는 이 라이브러리의 열렬한 팬으로, React Native 프로젝트에서 네비게이션을 처리할 때 항상 가장 먼저 선택하는 솔루션입니다. 그 이유는 훌륭하고 사용하기 쉬운 API를 제공하면서도 매우 유연하게 커스터마이징할 수 있기 때문입니다.
이 글을 작성하게 된 이유는 react-navigation 버전 5가 드디어 베타 단계를 거쳐 안정화(stable) 버전으로 출시되었기 때문입니다. 새 버전에는 여러 기능 변화가 있었고, 특히 기존과는 전혀 다른 방식으로 라우트를 선언할 수 있는 새로운 API 디자인이 도입되었습니다.
이번 글에서는 새롭게 바뀐 API들을 하나씩 살펴보고, 실제 애플리케이션에서 어떻게 활용할 수 있는지 알아보겠습니다.
원문은 saidhayani.com에 게시되었습니다.
설치하기
react-navigation 5의 설치 방법은 이전 버전(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는 라우트 초기화 방식에 동적인 요소를 도입했습니다. 이전에는 설정 파일에 라우트를 정적으로 정의해야 했습니다.
// @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)
이 기능은 커뮤니티에서 오랫동안 가장 많이 요청했던 부분입니다. 저 역시 기존의 정적(static) 방식 때문에 여러 번 문제를 겪었고, 네비게이션 동작을 동적으로 변경하는 일이 정말 어려웠습니다.
기존 방식 (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>
)
}
동적 옵션을 활용하면 인증 상태에 따라 타이틀을 변경할 수 있습니다. 예를 들어 사용자가 로그인된 경우 화면 제목을 해당 사용자의 이름으로 설정하거나, 헤더의 배경색을 자유롭게 바꿀 수 있습니다.
이 기능은 특히 동적 테마를 적용하거나 다크 모드(dark mode)를 구현하려는 경우에 큰 도움이 됩니다.
훅(Hooks)
지금까지 소개한 기능 중에서 개인적으로 가장 마음에 드는 것은 바로 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 덕분에 이런 복잡한 과정 없이도, 단 한 줄의 훅 호출로 Navigation 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",
}}
>
{/* Display the RouteName here */}
<Text style={styles.title}>{route.name}</Text>
</View>
)
}
useNavigationState 훅으로도 동일한 작업이 가능합니다. 이 훅은 네비게이션 상태(navigation state)에 직접 접근할 수 있게 해줍니다.
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는 확실히 정적(static)에서 동적(dynamic)으로 패러다임을 전환했습니다. React Native에서 네비게이션을 다루는 방식을 완전히 바꿔놓을 훌륭한 변화입니다. 동적 라우트는 react-navigation 사용자들이 오랫동안 요청해 온 핵심 기능이었으며, 이 새로운 방식을 통해 더 나은 사용자 네비게이션 경험을 만들 수 있을 것입니다.
읽어주셔서 감사합니다.
프로젝트를 위한 React Native 개발자를 찾고 계신가요? 언제든지 연락해 주세요!