React-navigation 타입스크립트 타입 지정

Dev-Yuns
9 min readMay 4, 2021
Photo by Tim Graf on Unsplash

React NavigationReact 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 을 만들고 내부에 각각 AuthStackMainBottomTab 네비게이션을 중첩했습니다.

navigation 구조 예시

React navigation에서 권장하는 일반적인 로그인 패턴은 RootStack에서 로그인 여부를 확인해서 AuthStackMainBottomTab 을 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를 이용해서 받았습니다. 해당 타입을 이용하여 navigatepush 등의 메서드를 이용할 때 타입 체킹을 할 수 있습니다. 특히 route이름은 setParams를 호출할 때 타입 체크를 위해 필요합니다.

Type for nested Navigator

지금까지 Navigator 단에서의 타입을 만드는 방법을 살펴봤다면 이제는 스크린 컴포넌트에서의 타입을 살펴보겠습니다. 만약 navigation이 중첩되지 않았다면 스크린에 주입되는 각 컴포넌트에 Props 타입을 아래와 같이 작성할 수 있습니다.

type Props = StackScreenProps<RootStackParamList, ‘Profile’>;

만약 네비게이션이 중첩 되었다면 (즉 현재 예시처럼 RootStackNavigatorScreen 컴포넌트로 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'>;
}

--

--