WIT 동아리에서 진행하는 프로젝트를 하던 중 제가 Navigation에 대한 개념을 정확하게 숙지하지 못하고 있다는 것을 깨달았습니다. 팀장님이 짜둔 구조를 몇 번을 봐도 이해하지 못해서 결국 늦은 밤에 여쭤보고 말았습니다...
여튼 이 기회에 다시 한번 리액트 네이티브의 네비게이션에 대해 정리해보려 합니다.
모바일 애플리케이션은 하나의 화면으로 구성되는 경우가 거의 없죠. 일반적으로 다양한 화면이 상황에 맞게 전환되면서 나타납니다. 그렇기 때문에 네비게이션은 모바일 애플리케이션에서 가장 중요한 기능 중 하나입니다.
리액트 네이티브에서는 네비게이션 기능을 지원하지 않으므로 외부 라이브러리를 이용해야 합니다.
yarn add react-native-navigation
리액트 네비게이션에는 NavigationConatiner 컴포넌트, Navigator 컴포넌트, Screen 컴포넌트가 있습니다.
Screen 컴포넌트는 화면으로 사용되는 컴포넌트로 name과 component 속성을 지정해야 합니다. name은 화면 이름으로 사용되고 component에는 화면으로 사용될 컴포넌트를 전달합니다. 화면으로 사용되는 컴포넌트에는 항상 navigation과 route가 props로 전달된다는 특징이 있습니다.
Navigator 컴포넌트는 화면을 관리하는 중간 관리자 역할로 네비게이션을 구성하며, 여러 개의 Screen 컴포넌트를 자식 컴포넌트로 갖고 있습니다.
NavigationContainer 컴포넌트는 네비게이션의 계층 구조와 상태를 관리하는 컨테이너 역할을 하며, 모든 네비게이션 구성 요소를 감싼 최상위 컴포넌트여야 합니다.
네비게이션에서 가장 기본적인 네비게이션은 스택 네비게이션입니다.
yarn add @react-navigation/stack
스택 네비게이션은 일반적으로 가장 많이 사용되는 네비게이션으로, 현재 화면 위에 다른 화면을 쌓으면서 화면을 이동하는 것이 특징입니다. 예를 들면, 채팅 애플리케이션에서 채팅방에 입장하는 상황이나 여러 목록 중에서 특정 항목의 상세 화면으로 이동할 때 많이 사용됩니다.
스택 네비게이션은 화면 위에 새로운 화면을 쌓으면서(push) 이동하기 때문에 이전 화면을 계속 유지합니다. 이런 구조 때문에 가장 위에 있는 화면을 들어내면(pop) 이전 화면으로 돌아갈 수 있다는 특징이 있습니다.
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;
createStackNavigator 함수를 이용해서 스택 네비게이션을 생성했습니다. 생성된 스택 네비게이션에는 화면을 구성하는 Screen 컴포넌트와 Screen 컴포넌트를 관리하는 Navigator 컴포넌트가 있습니다.
Navigator 컴포넌트 안에 Screen 컴포넌트를 자식 컴포넌트로 작성하고, 앞에서 만든 컴포넌트를 Screen 컴포넌트의 component로 지정했습니다. name에는 화면의 이름을 작성하는데, Screen 컴포넌트의 name은 반드시 서로 다른 값을 가져야 한다는 점에 유의해야 합니다.
스택 네비게이션에서 첫 번째 화면으로 나오는 화면은 Navigator 컴포넌트의 첫 번째 자식 Screen 컴포넌트입니다. 따라서 첫 번째 화면을 바꾸고 싶으면 Screen의 순서를 바꾸면 됩니다. 또는 initialRouteName 속성을 이용해 첫 번째 화면을 지정하는 방법도 있습니다.
이제 화면을 이동하는 방법입니다. 전에 책으로 공부했을 때는 props로 전달되는 navigation을 이용하는 방법을 사용했습니다. 그리고 프로젝트를 하면서 useNavagation Hook을 사용하는 방법을 익혔습니다. 두 가지 방법에 대해서 차례로 설명하겠습니다.
const Home = ({ navigation }) => {
return (
<Container>
<StyledText>Home</StyledText>
<Button
title="go to the list screen"
onPress={() => navigation.navigate('List')}
/>
</Container>
);
};
navigation에 있는 navigate 함수를 이용해서 원하는 화면의 이름을 전달하면 해당 화면으로 이동합니다. 단, 전달되는 화면의 이름은 Screen 컴포넌트의 name값 중 하나를 입력해야 합니다.
만약 이동하는 화면이 이전 화면의 상세 화면이라면, 상세 화면은 어떤 내용을 렌더링해야 하는지 전달받아야 합니다. navigate 함수를 이용할 때 두번째 파라미터에 객체를 전달해서 이동하는 화면에 필요한 정보를 함께 전달하는 기능이 있습니다.
이번에는 naviate 함수를 이용하여, List 화면에서 목록을 클릭하면 해당 항목의 정보와 함께 Item 화면으로 이동하도록 수정해보겠습니다.
const List = ({ navigation }) => {
const _onPress = item => {
navigation.navigate('Item', { id: item._id, name: item.name });
};
...
};
Item 화면으로 이동하면서 항목의 id와 name을 함께 전달하도록 작성했습니다. 전달된 내용은 컴포넌트의 props로 전달되는 route의 parmas를 통해 확인할 수 있습니다.
이번에는 Item 화면에서 전달되는 params를 이용하여 화면에 항목의 id와 name을 출력해보겠습니다.
const Item = ({ route }) => {
return (
<Container>
<StyledText>Item</StyledText>
<StyledText>ID: {route.params.id}</StyledText>
<StyledText>Name: {route.params.name}</StyledText>
</Container>
);
};
2. useNavigation Hook을 이용하는 방법
useNavigation은 navigation object에 대한 access를 부여하는 Hook입니다. 특히 컴포넌트로 직접 navigation prop를 전달하지 못할 때 유용합니다.
useNavigation은 해당 screen의 navigation prop을 반환합니다.
import * as React from 'react';
import { Button } from 'react-native';
import { useNavigation } from '@react-navigation/native';
function MyBackButton() {
const navigation = useNavigation();
return (
<Button
title="Back"
onPress={() => {
navigation.goBack();
}}
/>
);
}