배경
리액트 네이티브 프로젝트를 처음 시작할 때, 페이지 간 이동을 쉽게 구현하기 위해 `Tab Navigator`와 `Stack Navigator`를 함께 사용하고자 했다.
`Tab Navigator`는 하단에 탭 메뉴를 배치하여 사용자 경험을 향상시키는 데 유용하며,
`Stack Navigator`는 각 탭 내에서 화면 간 전환을 관리하는 데 효과적이다.
이 두 종류 말고도 'Drawer navigation' 도 존재하는데, 화면 간 이동을 위해 왼쪽(or 오른쪽)의 서랍을 사용하는 것이다.
(Sidenavigation을 만들 때 사용하는 것 같다.)
문제 발생
Tab Navigator와 Stack Navigator를 함께 사용하는 과정에서 두 개의 NavigationContainer를 사용하면 안 된다는 문제에 직면했다. 이 문제는 React Navigation 라이브러리의 기본 원칙에 위배되기 때문에 발생하였는데,
NavigationContainer는 네비게이션 상태를 관리하는 최상위 컴포넌트로, 앱 내에서 단 하나만 존재해야 한다.
이를 위반할 경우, 충돌이 발생하여 node_modules에서 에러가 발생하는 것을 볼 수 있다.
문제의 원인
`NavigationContainer`는 리액트 네이티브 앱의 네비게이션 상태를 전역적으로 관리한다. 따라서 앱의 루트 컴포넌트에 한 번만 정의되어야 하며, 여러 개의 `NavigationContainer`를 중복해서 사용하면 각각의 네비게이터들이 독립적으로 동작하게 되어 에러가 발생하게 된다.
해결 방법
`Stack Navigator`와 `Tab Navigator`를 동시에 사용하려면, 둘 중 하나를 다른 네비게이터의 자식으로 중첩하여 사용해야 한다.
예를 들어, `Tab Navigator`를 최상위 네비게이터로 설정하고, 각 탭 내부에 `Stack Navigator`를 배치하여 독립적인 화면 전환을 관리할 수 있다.
반대인 경우도 마찬가지!
아래는 `Stack Navigator`를 최상위에 두고, 특정 화면에 `Tab Navigator`를 중첩하여 사용하는 코드 예시이다.
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();
function HomeTabs() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
);
}
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="HomeTabs" component={HomeTabs} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
function HomeScreen() {
return (
// ... 홈 화면의 JSX 코드 ...
);
}
function SettingsScreen() {
return (
// ... 설정 화면의 JSX 코드 ...
);
}
function DetailsScreen() {
return (
// ... 상세 화면의 JSX 코드 ...
);
}
위 코드에서는 `HomeTabs`라는 컴포넌트 안에 `Tab Navigator`가 있고, `Stack Navigator`의 한 화면으로 이를 포함시킨 형태가 된다. 이렇게 하면 두 네비게이터가 충돌하지 않고 정상적으로 동작한다.
결론
리액트 네이티브 프로젝트에서 `Stack Navigator`와 `Tab Navigator`를 함께 사용할 때는 반드시 하나의 `NavigationContainer` 만 사용해야 한다. 이를 통해 앱의 네비게이션 상태를 일관성 있게 관리하고, 페이지 간 이동이 원활하게 이루어지도록 할 수 있다.
네비게이션의 Nesting navigators(네비게이터 중첩) 에 관한 공식 문서 정리
네비게이터 중첩(Nesting Navigators)은 다른 네비게이터의 화면 내부에 네비게이터를 렌더링하는 것을 의미한다.
예를 들어, Tab Navigator를 Stack Navigator의 한 화면으로 중첩할 수 있다. 아래는 Tab Navigator를 Stack Navigator 내부에 중첩한 예시이다.
function Home() {
return (
<Tab.Navigator>
<Tab.Screen name="Feed" component={Feed} />
<Tab.Screen name="Messages" component={Messages} />
</Tab.Navigator>
);
}
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={Home}
options={{ headerShown: false }}
/>
<Stack.Screen name="Profile" component={Profile} />
<Stack.Screen name="Settings" component={Settings} />
</Stack.Navigator>
</NavigationContainer>
);
}
위 예시에서 Home 컴포넌트에는 Tab Navigator가 포함되어 있으며, Stack Navigator 내의 한 화면으로 설정된다. 이는 Stack Navigator 내에서 Tab Navigator를 중첩하는 대표적인 방식이다.
- Stack.Navigator
- Home( Tab.Navigator)
- Feed( Screen)
- Messages( Screen)
- Profile( Screen)
- Settings( Screen)
- Home( Tab.Navigator)
구조는 이런 식이다.
아니면, Group Component를 사용해 보는 것은 어떨까?
Group components는 네비게이터 내에서 여러 화면을 그룹화하여 관리 목적으로 사용된다.
별도의 네비게이터를 사용하는 대신 Group Component를 활용할 수 있다는 장점이 있다.
또한, 그룹 내의 화면들에 공통된 옵션을 적용하는 데도 유용하다.
예를 들어, 특정 그룹의 모든 화면에 동일한 헤더 스타일을 적용할 수 있다.
Group component는 createXNavigator 함수에서 반환되는 Navigator 객체의 자식 요소로 사용된다.
아래 예시는 Stack Navigator를 생성하고, 이를 그룹화하는 방법을 보여준다.
const Stack = createStackNavigator(); // Stack은 Screen과 Navigator 속성을 포함한다.
<Stack.Navigator>
<Stack.Group
screenOptions={{ headerStyle: { backgroundColor: 'papayawhip' } }}
>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Group>
<Stack.Group screenOptions={{ presentation: 'modal' }}>
<Stack.Screen name="Search" component={SearchScreen} />
<Stack.Screen name="Share" component={ShareScreen} />
</Stack.Group>
</Stack.Navigator>
이처럼 Stack.Group을 사용하면 화면을 그룹화하여 관리하기 쉬워지고, 네비게이터 중첩 없이도 원하는 UI를 구현할 수 있다!
필자는 Stack Navigator를 사용하면서도, 특정 화면에서만 탭 바를 노출하는 등, 사용자 경험을 고려한 네비게이션 구조를 반영하기 위해 해당 문서를 참고하였다.
'개발 > 프론트엔드' 카테고리의 다른 글
| 브라우저가 리소스를 로드하는 과정에서 성능을 최적화하는 방법 (3) | 2024.10.05 |
|---|---|
| 프론트엔드 개발자가 알아야 할 백엔드 JWT 인증 및 권한 관리 (1) | 2024.09.29 |
| Flux 패턴 (2) | 2024.09.17 |
| 프론트엔드 개발자가 많이 사용하는 그 프레임워크(또는 라이브러리)들을 비교해보쟈 (3) | 2024.09.08 |
| 리액트를 시작할 때 꼭 알아야 하는 것과 작업환경 설정 (5) | 2023.05.09 |