React Navigation 공식 라이브러리는 컴포넌트 간 이동인 라우팅 기능을 제공
- 각 navigator(stack, bottomTab 등)을 create할 때 타입을 지정해주면, 각 하위의 컴포넌트(스크린)들에 자동으로 내려지는 props(route, navigation)에 대한 타입 체크와 자동 완성이 가능해짐
https://reactnavigation.org/docs/typescript/
type RootStackParamList = {
Home: undefined;
Profile: { userId: string };
Feed: { sort: 'latest' | 'top' } | undefined;
};
import { createStackNavigator } from '@react-navigation/stack';
const RootStack = createStackNavigator<RootStackParamList>();
<RootStack.Navigator initialRouteName="Home">
<RootStack.Screen name="Home" component={Home} />
<RootStack.Screen
name="Profile"
component={Profile}
initialParams={{ userId: user.id }}
/>
<RootStack.Screen name="Feed" component={Feed} />
</RootStack.Navigator>
개별 스크린에서 타입을 체크하기 위해서는, 각 스크린이 내려받는 props(navigation, route)에 대해 annotate 해야 함
StackNavigationProp
이 가지는 parameter는 위에서 생성한 param list object이고, 두번째 parameter는 현재 route 이름임. import { StackNavigationProp } from '@react-navigation/stack';
type ProfileScreenNavigationProp = StackNavigationProp<
RootStackParamList,
'Profile'
>;
type Props = {
navigation: ProfileScreenNavigationProp;
};
여러 navigator가 중첩되어 있는 경우,
screen
과params
을 중첩되어 있는 스크린에 전달하므로서 스크린들을 navigate 할 수 있음navigation.navigate('Home', { screen: 'Feed', params: { sort: 'latest' }, });
NavigatorScreenParams
)import { NavigatorScreenParams } from '@react-navigation/native';
type TabParamList = {
Home: NavigatorScreenParams<StackParamList>;
Profile: { userId: string };
};
CompositeNavigationProp
)CompositeNavigationProp
의 첫번째 인자는 주된 navigation type이고, 두번째 인자는 2순위 navigation type임(부모 navigator) => 스크린 이름은 첫번째 인자에서만 가짐import { CompositeNavigationProp } from '@react-navigation/native';
import { BottomTabNavigationProp } from '@react-navigation/bottom-tabs';
import { StackNavigationProp } from '@react-navigation/stack';
type ProfileScreenNavigationProp = CompositeNavigationProp<
BottomTabNavigationProp<TabParamList, 'Profile'>,
StackNavigationProp<StackParamList>
>;
type ProfileScreenNavigationProp = CompositeNavigationProp<
BottomTabNavigationProp<TabParamList, 'Profile'>,
CompositeNavigationProp<
StackNavigationProp<StackParamList>,
DrawerNavigationProp<DrawerParamList>
>
>;
useNavigation
const navigation = useNavigation<ProfileScreenNavigationProp>();
useRoute
const route = useRoute<ProfileScreenRouteProp>();
- 상위 stackNavigator : "HomeTabs", "MainList", "ContentDetail
- 차상위 bottomTabNavigator: "Home", "ChattingList", "LikedContents", "Setting"
//RootNavigator.tsx
...
//하단의 type 적용을 받는 stackNavigator 생성
const Stack = createStackNavigator<RootStackParamList>();
interface Props {}
export default function RootNavigator({}: Props): ReactElement {
return (
<Stack.Navigator initialRouteName="HomeTabs" headerMode="float">
<Stack.Screen
name="HomeTabs"
component={BottomTabNavigator}
/>
<Stack.Screen
name="MainList"
component={MainListScreen}
/>
<Stack.Screen
name="ContentDetail"
component={ContentDetailScreen}
/>
</Stack.Navigator>
);
}
// undefined는 해당 스크린에 넘겨받는 params가 없다는 의미
export type RootStackParamList = {
HomeTabs: undefined;
MainList: undefined;
ContentDetail: {contentId: number};
};
// BottomTabNavigator.tsx
...
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
...
import {NavigatorScreenParams, useTheme} from '@react-navigation/native';
import {RootStackParamList} from './RootNavigator';
const Tab = createBottomTabNavigator<TabNavigatorParamList>();
...
export default function BottomTabNavigator({}: Props): ReactElement {
..
return (
<Tab.Navigator initialRouteName={'Home'}>
{bottomTabInfos.map(EachTab => {
return (
<Tab.Screen
key={EachTab.id}
name={EachTab.name}
component={EachTab.component}
options={{
tabBarLabel: EachTab.tabBarLabel,
tabBarIcon: () => (
<Icon name={EachTab.iconName} size={30} color={theme} />
),
}}
/>
);
})}
</Tab.Navigator>
);
}
C
export type TabNavigatorParamList = {
Home: undefined;
ChattingList: undefined;
LikedContent: undefined;
Setting: undefined;
};
CompositeNavigationProp
을 이용하여 첫번째 인자로 BottomTabNavigator의 PramList를 이용한 NavigationProp을, 두번째 인자로 상위 StackNavigator에서의 RootStackParamList를 넣어 모두 포함시킬 수 있도록 구현//MainMapScreen.tsx
...
import {CompositeNavigationProp} from '@react-navigation/native';
import {StackNavigationProp} from '@react-navigation/stack';
import {BottomTabNavigationProp} from '@react-navigation/bottom-tabs';
import {TabNavigatorParamList} from '../../../navigators/BottomTabNavigator';
import {RootStackParamList} from '../../../navigators/RootNavigator';
...
interface Props {
navigation: CompositeNavigationProp<
BottomTabNavigationProp<TabNavigatorParamList, 'Home'>,
StackNavigationProp<RootStackParamList>
>;
}
export default function MainMapScreen({navigation}: Props): ReactElement {
...
navigation.navigate("")
...
}
- StackNavigator의 navigtion prop과 BottomTabNavigator의 navigation prop을 모두 포함하여 최하위 스크린에서 사용가능
- 최하위 레벨의 스크린에서 부모레벨 혹은 동일 레벨의 스크린 모두를 자유롭게 이동할 수 있음