React Navigation은 React native
에서 네비게이션을 구현할 수 있는 패키지입니다. BottomTabNavigation
, DrawerNavigation
, Stacknavigation
등 다양한 네비게이션을 통해 모바일에서 통용되는 UX를 제작할 수 있습니다.
기본 패키지는 다음과 같이 설치할 수 있으며,
yarn add @react-navigation/native
프로젝트가 managed workflow이거나 bare workflow냐에 따라 의존성 패키지 설치 방법이 조금 다릅니다.
- in expo
expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view
- Bare workflow
yarn add react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view
네비게이션은 화면을 표현하는 View
들의 최상단에 위치합니다. Provider
들을 제외하고 View
를 표현하는 가장 상단 컴포넌트(보통 App)를 NavigationContainer
로 감싸주세요.
저는 RootStackNavigation
을 만들고 내부에 각각 AuthStack
과 MainBottomTab
네비게이션을 중첩했습니다.
React navigation에서 권장하는 일반적인 로그인 패턴은 RootStack에서 로그인 여부를 확인해서 AuthStack
과 MainBottomTab
을 Conditional하게 보여주는 것입니다.
Type for Navigator
아래는 RootStackNavigator
의 예시 코드입니다. 각 네비게이션은 각각의 자체 라이브러리를 구성하고 있으므로, StackNavigator
를 사용하기 위해서 따로 설치를 진행해주어야 합니다.
yarn add @react-navigation/stack
예시 코드
import {
StackNavigationProp,
createStackNavigator,
} from '@react-navigation/stack';import AuthNavigator from './AuthStackNavigator';
import {NavigationContainer} from '@react-navigation/native';
import React, {useState} from 'react';
import MainBottomTabNavigator from './MainStackNavigator';export type RootStackParamList = {
default: undefined;
AuthNavigator: undefined;
MainNavigator: undefined;
};export type RootStackNavigationProps<
T extends keyof RootStackParamList = 'default'
> = StackNavigationProp<RootStackParamList, T>;const Stack = createStackNavigator<RootStackParamList>();function RootNavigator(): React.ReactElement {
const [user, setUser] = useState(false);return (
<NavigationContainer>
<Stack.Navigator>
{!user ? (
<Stack.Screen name="AuthNavigator" component={AuthNavigator} />
) : (
<Stack.Screen
name="MainNavigator"
component={MainBottomTabNavigator}
/>
)}
</Stack.Navigator>
</NavigationContainer>
);
}export default RootNavigator;
위 코드에서 Type-safe한 네비게이션 구조를 위해 먼저 RootStackParamList
타입을 정의해주었습니다. export
를 한 이유는 추후 네비게이션 아래의 스크린 컴포넌트에 주입되고 있는 컴포넌트에서 타입으로 사용할 것이기 때문입니다.
ParamList
내부에는 각각 Screen
컴포넌트의 이름과 해당 컴포넌트에 인자로 넘겨질 param
을 정의할 수 있습니다. undefined
이라고 한 것은 넘길 인자가 없다는 뜻입니다. 만약 param | undefined
와 같이 union 타입을 사용한다면 해당 파라미터는 옵셔널하다는 의미입니다.
RootStackParamList
는 하단에서 CreateStackNavigator
에 제네릭으로 주입해줍니다. 이를 통해 Type checking
과 자동 완성 기능을 제공해줄 수 있습니다.
그 아래의 RootStackNavigationProps
또한 이후 stackNavigation
에 포함되는 각 컴포넌트에서 사용될 타입으로, 먼저 정의한 ParamList
의 키값들을 T
로 받습니다.
다음으로 Screen
컴포넌트에서 navigation
, route
등의 props 타입을 정의하기 위해 StackNavigationProps
를 사용합니다. 해당 타입은 각 네비게이션 패키지 마다 유사한 이름으로 제공됩니다.
이 타입은 제네릭의 첫번째 인자로 ParamList
를 받고, 두번째 인자로 현재 Route
이름인 RouteName
을 받습니다. 저는 제네릭 T
를 이용해서 받았습니다. 해당 타입을 이용하여 navigate
나 push
등의 메서드를 이용할 때 타입 체킹을 할 수 있습니다. 특히 route
이름은 setParams
를 호출할 때 타입 체크를 위해 필요합니다.
Type for nested Navigator
지금까지 Navigator 단에서의 타입을 만드는 방법을 살펴봤다면 이제는 스크린 컴포넌트에서의 타입을 살펴보겠습니다. 만약 navigation
이 중첩되지 않았다면 스크린에 주입되는 각 컴포넌트에 Props
타입을 아래와 같이 작성할 수 있습니다.
type Props = StackScreenProps<RootStackParamList, ‘Profile’>;
만약 네비게이션이 중첩 되었다면 (즉 현재 예시처럼 RootStackNavigator
의 Screen
컴포넌트로 StackNavigator
컴포넌트를 주입해주었다면) 네비게이션 중첩 관계를 타이핑해주어야 합니다.
CompositeNavigationProp
라는 타입을 사용하면 중첩된 네비게이션 구조에서 props간의 위계 관계를 표현할 수 있습니다. CompositeNavigationProp
은 2가지 타입을 파라미터로 받습니다. 첫번째는 자신이 속한 navigation type을 받고, 두번째는 상위 navigation을 받습니다.
예를 들어 RootStack 내부에 중첩된 AuthStack 컴포넌트는 아래와 같이 타이핑할 수 있습니다.
export type AuthNavigatorParamList = {
SignIn: undefined;
SignUp: undefined;
Welcome: undefined;
};type NavigationProps<
T extends keyof AuthNavigatorParamList = 'SignIn'
> = StackNavigationProp<AuthNavigatorParamList, T>;export type AuthStackNavigationProps<
T extends keyof AuthNavigatorParamList = 'SignIn'
> = CompositeNavigationProp<
NavigationProps<T>,
RootStackNavigationProps<'AuthNavigator'>
>;const Stack = createStackNavigator<AuthNavigatorParamList>();
만약 중첩된 navigation이 더 많다면 compostenaviagtionProps를 중첩함으로써 관계를 표현할 수 있습니다.
Navigator
단에서 필요한 대부분의 타입을 정의해주었기 때문에, Screen
컴포넌트 내부에서는 Props
타입만 정의해주면 됩니다. 네비게이션 컴포넌트에서 제네릭을 사용하여 T
타입을 선언해주었기 때문에, 스크린 컴포넌트의 이름인 SignIn
만 주입해주면 됩니다. T
타입은 ParamList
의 키 값을 받을 수 있습니다.
interface Props {
navigation: AuthStackNavigationProps<'SignIn'>;
route: RouteProp<AuthNavigatorParamList, 'SignIn'>;
}