React Navigation V5 네비게이션 소식 파해치기 및 타입별 예제

dooboolab
dooboolab
Nov 24, 2019 · 16 min read

이번 포스트에는 react-navigation v5 마이그레이션에 이어서 react-navigation v5 네비게이션 소식을 깊게 파해치고 네비게이션 종류들을 알아보며 실전 예제들을 화면으로 보겠습니다.

현재 `next` 패키지는 v5입니다.

우선 react-navigation v2에서 나온 SwitchNavigator2019년 11월 24일 기준 아직 나오지 않았습니다. 아직 개발이 안된 것인지 장기적으로 deprecated 되는지는 확실한 답변을 받지 못했습니다. Work around는 여기에 소개되어 있지만 저희 컨트리뷰터 분이 시도해본 결과 알 수 없는 버그로 아직 제대로 사용해보지는 못했습니다.

수정

SwitchNavigator는 deprecated 된 것이 맞네요. 관련 내용을 찾기 어려웠지만 하나씩 읽어보고 발견하였습니다. SwitchNavigator를 사용하는 것보다 아래와 같이 해주는 것이 유지보수가 훨씬 편하다고 말해주고 있습니다.

React Navigation V5에서 SwitchNavigator를 사용하지 않은 authentication flow

react-navigation v5에서는 createNativeStackNavigator 라는 새로운 방식으로 StackNavigator를 만드는 방법이 나왔습니다. 실제로 테스트 하면서 알았던 사실인데 createNativeStackNavigatorcreateStackNavigator를 같이 사용할 수 없는 구조로 되어있습니다. 현재는 둘중의 하나로 StackNavigator를 통일해야합니다. 처음에는 SwitchNavigatorcreateNativeStackNavigator로 대체 되는줄 알았는데 react-navigation 포스트를 읽고 오해를 했다는 것을 알았습니다.

위에서 언급한 포스트를 읽어보시면 아시겠지만 createNativeStackNavigatorcreateStackNavigator와 동일한 feature를 구사하지만 native에 더욱 가깝게 navigation을 묘사할 수 있도록 도와줍니다.

이미지 출처: react-navigation 공식 블로그

위에서 보시면 얼마나 네비게이션 헤더가 부드럽게 전환 되는지 볼 수 있습니다. 그동안 react-navigation 팀은 react-native-navigation 혹은 navigation-router 와 같이 v4 때까지는 native에 직결되서 네비게이션을 개발하지 않았습니다. 이유는 위에서 나온 것처럼 javascript 사이드에서 대부분의 ui/ux가 개발이 되기 때문에 이러한 접근은 새로운 feature들을 담거나 커스터마이징을 유연하게 해주었습니다. 또한 위 접근은 하여금 많은 개발자들에게 빠르게 프로덕션 레벨에서 쓰이는 다양한 feature들을 제공해줄 수 있었습니다.

그리고 어느정도 stability에 이른 지금 native 경험을 사용자들에게 주기 위한 고민을 시작했습니다. 그래서 나온 것이 NativeStackNavigator입니다. 이렇게 이야기하면 NativeStackNavigator가 더 좋고 무조건 이걸 써야하는 것처럼 들릴 수 있습니다만 그렇지 않습니다. 여전히 네이티브 네비게이션은 네이티브 api에서 노출되지 않는 부분 때문에 굉장히 제한적이기 때문입니다. 유연성과 확장성을 고려하면 여전히 자바스크립트 네비게이션이 좋다고 이야기하고 있습니다. 결국은 서비스의 목적에 따라 선택적으로 둘을 사용해야 합니다.


지금부터는 react-navigation v5에 있는 네비게이션들을 직접 써보겠습니다.

실제로 StackNavigator를 담은 화면입니다. NativeStackNavigatorStackNavigator의 차이는 육안으로 느끼지는 못하였지만 사용법이 조금 다르며 같이 쓸 수 없다는 것을 확인하였습니다.

  • StackNavigator는 각각의 화면을 Stack과 같이 쌓는 네비게이션입니다.
import React from 'react';
import Screen1 from '../screen/Screen1';
import Screen2 from '../screen/Screen2';
import Screen3 from '../screen/Screen3';
import Screen4 from '../screen/Screen4';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { useThemeContext } from '../../providers/ThemeProvider';
const Stack = createNativeStackNavigator();function RootNavigator(): React.ReactElement {
const { theme } = useThemeContext();
return (
<Stack.Navigator
screenOptions={{
headerStyle: {
backgroundColor: theme.background,
},
headerTitleStyle: { color: theme.fontColor },
headerTintColor: theme.tintColor,
}}
>
<Stack.Screen name="Screen1" component={Screen1} />
<Stack.Screen name="Screen2" component={Screen2} />
<Stack.Screen name="Screen3" component={Screen3} />
<Stack.Screen name="Screen4" component={Screen4} />
</Stack.Navigator>
);
}
export default RootNavigator;

유래는 안드로이드에서 생겨난 네비게이션입니다. 아래와 같이 버튼을 눌렀을 때 옆에 메뉴 슬라이더를 열었다 닫을 수 있습니다. 왼쪽 메뉴에서도 오른쪽 화면을 바꿀 수 있습니다.

import { DrawerItem, createDrawerNavigator } from '@react-navigation/drawer';
import React, { ReactElement } from 'react';
import { ScrollView, StyleSheet } from 'react-native';
import DrawerScreen1 from '../screen/DrawerScreen1';
import DrawerScreen2 from '../screen/DrawerScreen2';
import { useSafeArea } from 'react-native-safe-area-context';
const Drawer = createDrawerNavigator();const styles = StyleSheet.create({
container: {
flex: 1,
},
});
function CustomDrawerContent({ drawerPosition, navigation }): ReactElement {
const insets = useSafeArea();
return (
<ScrollView
contentContainerStyle={[
{
paddingTop: insets.top + 4,
paddingLeft: drawerPosition === 'left'
? insets.left : 0,
paddingRight: drawerPosition === 'right'
? insets.right : 0,
},
]}
style={styles.container}
>
<DrawerItem
label="Screen1"
onPress={(): void => {
navigation.navigate('DrawerScreen1');
}}
/>
<DrawerItem
label="Screen2"
onPress={(): void => {
navigation.navigate('DrawerScreen2');
}}
/>
<DrawerItem
label="Close"
onPress={(): void => {
navigation.closeDrawer();
}}
/>
</ScrollView>
);
}
function Navigator(): ReactElement {
return (
<Drawer.Navigator
drawerContent={(props): ReactElement => (
<CustomDrawerContent {...props} />
)}
>
<Drawer.Screen
name="DrawerScreen1"
component={DrawerScreen1} />
<Drawer.Screen
name="DrawerScreen2"
component={DrawerScreen2} />
</Drawer.Navigator>
);
}
export default Navigator;

BottomTabNavigator

ios에서 주로 쓰는 네비게이션입니다. 아래 버튼들이 있고 버튼을 누를 때마다 화면들을 전환시킵니다.

import React, { ReactElement } from 'react';import { IC_MASK } from '../../utils/Icons';
import { Image } from 'react-native';
import Screen1 from '../screen/Screen1';
import Screen2 from '../screen/Screen2';
import Screen3 from '../screen/Screen3';
import Screen4 from '../screen/Screen4';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
const Tab = createBottomTabNavigator();const TabBarIcon = (focused: boolean): ReactElement => {
return (
<Image
style={{
width: focused ? 24 : 18,
height: focused ? 24 : 18,
}}
source={IC_MASK}
/>
);
};
function Navigator(): ReactElement {
return (
<Tab.Navigator
screenOptions={{
tabBarIcon: ({ focused }): ReactElement =>
TabBarIcon(focused),
}}
>
<Tab.Screen
name="Screen1"
component={Screen1}
options={{
tabBarLabel: 'Screen1',
tabBarIcon: ({ focused }): ReactElement =>
TabBarIcon(focused),
}}
/>
<Tab.Screen name="Screen2" component={Screen2} />
<Tab.Screen name="Screen3" component={Screen3} />
<Tab.Screen name="Screen4" component={Screen4} />
</Tab.Navigator>
);
}
export default Navigator;

MaterialTopTabNavigator

안드로이드 머터리얼 디자인가이드에 따른 위에 배치 되어 있는 네비게이션입니다. 기본적으로 좌우로 화면을 슬라이드할 수 있으며 indicator도 함께 슬라이드 됩니다.

import React, { ReactElement } from 'react';import Screen1 from '../screen/Screen1';
import Screen2 from '../screen/Screen2';
import Screen3 from '../screen/Screen3';
import Screen4 from '../screen/Screen4';
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
const Tab = createMaterialTopTabNavigator();function Navigator(): ReactElement {
return (
<Tab.Navigator
tabBarOptions={{
labelStyle: { fontSize: 12 },
style: { backgroundColor: 'blue' },
}}
>
<Tab.Screen name="Screen1" component={Screen1} />
<Tab.Screen name="Screen2" component={Screen2} />
<Tab.Screen name="Screen3" component={Screen3} />
<Tab.Screen
name="Screen4"
component={Screen4}
options={{ tabBarLabel: 'Custom4' }}
/>
</Tab.Navigator>
);
}
export default Navigator;
  • tabBarOptionsdefaultNavigationOption을 줄 때 사용되며 개별로 navigationOption을 주고 싶다면 options 파라미터 안에다가 속성값을 주면 됩니다.

MaterialBottomTabNavigator

이번에는 안드로이드 머터리얼 디자인가이드에 따른 아래에 배치 되어 있는 네비게이션입니다. 기본적으로 약간 다른점은 해당 화면이 활성화 되었을 때 버튼 안에 내용물들이animating 되면서 커집니다. 또한 활성화가 되지 않은 버튼들은 text가 보이지 않습니다. 기본적으로는 아래와 같지만 물론 customizing이 가능합니다.

import React, { ReactElement } from 'react';import { IC_MASK } from '../../utils/Icons';
import { Image } from 'react-native';
import Screen1 from '../screen/Screen1';
import Screen2 from '../screen/Screen2';
import Screen3 from '../screen/Screen3';
import Screen4 from '../screen/Screen4';
import { createMaterialBottomTabNavigator } from '@react-navigation/material-bottom-tabs';
const Tab = createMaterialBottomTabNavigator();const TabBarIcon = (focused: boolean): ReactElement => {
return (
<Image
style={{
width: focused ? 24 : 18,
height: focused ? 24 : 18,
}}
source={IC_MASK}
/>
);
};
function Navigator(): ReactElement {
return (
<Tab.Navigator
screenOptions={{
tabBarIcon: ({ focused }): ReactElement =>
TabBarIcon(focused),
}}
>
<Tab.Screen
name="Screen1"
component={Screen1}
options={{
tabBarLabel: 'Screen1',
tabBarIcon: ({ focused }): ReactElement =>
TabBarIcon(focused),
}}
/>
<Tab.Screen name="Screen2" component={Screen2} />
<Tab.Screen name="Screen3" component={Screen3} />
<Tab.Screen name="Screen4" component={Screen4} />
</Tab.Navigator>
);
}
export default Navigator;

마치며

React Navigation v5는 디자인적으로 많은 변화를 주었지만 기존의 Navigation들은 과거의 것들을 잘 유지하고 있습니다. SwitchNavigator가 빠진 것은 아쉬움이 남지만 native를 더 잘 소화할 수 있는 NativeStackNavigation이 앞으로의 개발에서 많이 기대됩니다. 아직까지는 엄청난 효용을 느끼진 못했지만 앞으로 써보면서 그러한 상황이 생겨서 보완하는 계기가 생기면 새로운 포스트로 찾아 뵙겠습니다.

위 예제들은 React Navigation V5 Example 레포지토리에 있으며 궁금하신 분들은 받아서 돌려보시면 됩니다 :)

앞으로 React Navigation V5를 선두적으로 도입하여 사용하고 있는 오픈소스 HackaTalk에도 관심을 가져주시면 좋겠습니다.

react-native-seoul

React Native community in Seoul

More From Medium

More on Dooboolab from react-native-seoul

More on React Native from react-native-seoul

More on React Native from react-native-seoul

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade