지원하는 내비게이션의 종류는 스택 내비게이션, 탭 내비게이션, 드로어 내비게이션이다.
책에서는 내비게이션 5버전으로 실습을 하는데, 찾아보니 현재 버전은 7이다!

Screen 컴포넌트는 화면으로 사용되는 컴포넌트로 name(화면 이름)과 component(화면으로 사용될 컴포넌트) 속성을 지정해야 한다. 화면으로 사용되는 컴포넌트에는 항상 navigation과 route가 props로 전달된다.
Navigator컴포넌트는 화면을 관리하는 중간 관리자 역할이다.
NavigationContainer컴포넌트는 내비게이션 계층 구조와 상태를 관리하는 컨테이너 역할을 한다. 모든 내비게이션 구성요소를 감싼 최상위 컴포넌트여야 한다.
부모의 설정은 자식에게도 적용되므로, 공통적으로 적용하고 싶은 속성의 경우에는 Navigator, 각 화면에 적용하고 싶은 속성은 Screen을 이용한다. 작은 범위의 설정일수록 우선순위가 높다.
폴더 구조는 다음과 같이 한다.
react-native-navigation
└── src
├── navigations
├── screens
│── App.js
└── App.js
리액트 내비게이션 라이브러리를 설치한다.
npm install --save @react-navigation/native
필요한 종속성을 설치한다.
expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view
스택 네비게이션에 필요한 라이브러리를 설치한다.
npm install greact-navigation/stack
스택 네비게이션은 일반적으로 가장 많이 사용되며 현재 화면 위에 다른 화면을 쌓으며 이동한다.
import React from 'react';
import { createStackNavigator } from '@react-navigation/stack';
import Home from '../screens/Home';
import List from '../screens/List';
import Item from '../screens/Item';
const Stack = createStackNavigator();
const StackNavigation = () => {
return (
<Stack.Navigator>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="List" component={List} />
<Stack.Screen name="Item" component={Item} />
</Stack.Navigator>
);
};
export default StackNavigation;
가장 먼저 Home 화면이 뜨고, 다른 화면으로 이동할 수 있으며, 뒤로가기 하면 이전 화면으로 돌아간다. 첫번째로 나오는 화면은 Navigator의 첫번째 자식이며 순서를 바꾸면 다른 화면이 첫 화면으로 나온다.
‹Stack.Navigator initialRouteName=" Home">
혹은 initialRouteName 속성을 이용해 첫번째 화면을 지정한다.
const Home = ({ navigation }) => {
return (
<Container>
<StyledText>Home</StyledText>
<Button
title="go to the list screen"
onPress={() => navigation.navigate('List')}
/>
</Container>
);
};
navigation함수를 이용해서 원하는 화면의 이름을 전달하면 해당 화면으로 이동한다. 전달되는 화면의 이름은 Screen컴포넌트의 name값 중 하나를 입력해야 한다.
//List.js
const List = ({ navigation }) => {
const _onPress = item => {
navigation.navigate('Detail', { id: item._id, name: item.name });
};
//Item.js
const Item = ({ route }) => {
return (
<Container>
<StyledText>Item</StyledText>
<StyledText>ID: {route.params,id}</StyledText>
<StyledText>Name: {route.params,name}</StyledText>
</Container>
);
};
List에서 상세 Item화면으로 이동할 때, id와 name을 함께 전달한다. 전달된 내용은 컴포넌트의 props로 전달되는 route의 params를 통해 확인할 수 있다.
<Stack Navigator
initialRouteName="Home"
screenOptions={{cardStyle: { backgroundColor: '#ffffff' } }}
>
navigation이 화면 전체를 차지하고 있지 않아 내부는 스타일이 적용 안 될 수도 있다. 그 땐 cardStyle을 이용한다.
헤더의 타이틀은 Screen의 name속성을 기본값으로 한다. 하지만 name 속성을 이용하는 곳을 모두 찾아다니며 수정하는 것은 번거롭다.
<Stack.Screen
name="List"
component={List}
options={{headerTitle: 'List Screen' }}
/>
headerTitle속성을 이용하면 name을 바꿀 필요 없이 헤더의 타이틀이 변경된다.
headerStyle: {
height: 110,
backgroundColor: '#95a5a6',
borderBottomWidth: 5,
borderBottomColor: '#34495e',
},
headerTitleStyle: { color: "#ffffff', fontSize: 24},
headerTitleAlign: 'center'
헤더의 스타일 변경은 headerStyle, headerTitleStyle, 정렬에는 headerTitleAlign 을 이용한다. headerTitleAlign은 center, left 두가지 만 값으로 설정할 수 있으며 ios는 center, andoird는 left가 기본 값이다.
headerTitle: ({ style )) => (
<MaterialCommunityIcons name="react" style={style} />
),
타이틀에 문자열이 아닌 다른 것을 이용하고 싶다면 headerTitle을 사용한다
이전 화면으로 이동할 때, 헤더 왼쪽에 뒤로가기 버튼이 생성되는데 ios는 이전 화면의 타이틀을 버튼의 타이틀로 보여주고, android는 그러지 않는다는 차이점이 있다.
options= {{
headerTitle: "List Screen',
headerBackTitleVisible: true,
}}
headerBackTitleVisible를 사용하여 버튼 타이틀 렌더링 유무를 동일하게 설정할 수 있다.
헤더를 숨길 때엔 headerMode나 headerShown을 이용한다. headerMode에는 다음 중 헤더 렌더링 방식을 선택할 수 있다
headerShown은 특정 화면 또는 전체 Navigator에서 헤더 표시 여부를 제어한다. 보통 첫 화면(Home)에서만 헤더 숨기기 등에서 headerShown을 활용한다.
보통 화면 위나 아래에 위치하여 탭 버튼을 누르면 연결된 화면으로 이동하는 방식이다.
npm install @react-navigation/bottom-tabs
라이브러리를 설치한다.
//screens/TabScreens.js
import React from 'react';
import styled from 'styled-components/native';
const Container = styled.View`
flex: 1;
justify-content: center;
align-items: center;
background-color: #54b7f9;
`;
const StyledText = styled.Text`
font-size: 30px;
`;
export const Mail = () => {
return (
<Container>
<StyledText>Mail</StyledText>
</Container>
);
};
export const Meet = () => {
return (
<Container>
<StyledText>Meet</StyledText>
</Container>
);
};
export const Settings = () => {
return (
<Container>
<StyledText>Settings</StyledText>
</Container>
);
};
//navigations/Tab.js
import React from 'react';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { Mail, Meet, Settings } from '../screens/TabScreens';
const Tab = createBottomTabNavigator();
const TabNavigation = () => {
return (
<Tab.Navigator>
<Tab.Screen name="Mail" component={Mail} />
<Tab.Screen name="Meet" component={Meet} />
<Tab.Screen name="Settings" component={Settings} />
</Tab.Navigator>
);
};
export default TabNavigation;
스택 네비게이션과 동일하게 처음 보여지는 화면은 첫번째 자식이며 initialRouteName을 사용하여 첫 화면을 지정할 수도 있다.
const TabIcon = ({ name, size, color }) => {
return <MaterialCommunityIcons name={name} size={size} color={color} />;
};
...
<Tab.Screen
name="Mail"
component={Mail}
options={{
tabBarIcon: props =>
TabIcon({ ...props, name: 'email' }),
}}
/>
tabBarIcon을 이용하여 탭바에 아이콘을 삽입할 수 있다.
const TabNavigation = () => {
return (
<Tab.Navigator
initialRouteName="Settings"
screenOptions={({ route }) => ({
tabBarIcon: props => {
let name = '';
if (route.name === 'Mail') name = 'email';
else if (route.name === 'Meet') name = 'video';
else name = 'settings';
return TabIcon({ ...props, name });
},
})}
>
<Tab.Screen name="Mail" component={Mail} />
<Tab.Screen name="Meet" component={Meet} />
<Tab.Screen name="Settings" component={Settings} />
</Tab.Navigator>
);
};
각각 지정하지 않고 screenOptions을 이용해 한 곳에서 관리할 수도 있다.
<Tab.Screen
name="Mail"
component={Mail}
options={{
tabBarLabel: 'Inbox',
Screen에서 tabBarLabel값을 설정하여 탭 버튼의 라벨을 변경할 수 있다.
<Tab.Navigator
initialRouteName="Settings"
tabBarOptions={{
labelPosition: 'beside-icon',
라벨을 아이콘 옆에 위치시키고 싶다면 labelPosition을 beside-icon으로 설정한다. showlabel을 false로 설정하면 라벨이 보이지 않는다.