RN 프로젝트를 진행하며 현재 앱 기획에 맞게 Navigator, Screen 구조를 어떤식으로 잡으면 좋을지 고민해보았다.
우선 유저이탈률을 줄이기 위해 로그인은 앱 진입 시점이 아닌, 로그인이 필요할 때 로그인 스크린이 Stack에 쌓인다.
또한 앱 진입 시 메인에는 TabNavigator가 존재하고 하단에는 여러개의 Tab이 존재하는 구조였다.
export type AuthStackParamList = {
Login: { redirectTo?: string } | undefined;
Signup: undefined;
};
export type RootStackParamList = {
Main: undefined;
Auth: { redirectTo?: string } | undefined; // 로그인 후 돌아갈 곳 (옵션)
};
export type EventStackParamList = {
EventDetail: { eventId: string };
EventApply: undefined;
ApplicantInfo: undefined;
Ticket: undefined;
AddPhotoTicket: undefined;
};
export type ProfileStackParamList = {
ProfileEdit: undefined;
ProfileSetting: undefined;
};
export type ChatStackParamList = {
ChatDetail: { chatId: string };
};
export type TabStackParamList = {
Chat: undefined;
Event: undefined;
Profile: undefined;
};
우선 네비게이션 타입을 위처럼 잡았다.
import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import { RootStackParamList } from "app/types/navigation";
import AuthNavigator from "./AuthNavigator";
import MainNavigator from "./MainNavigator";
type Props = {};
const RootStack = createNativeStackNavigator<RootStackParamList>();
export default function RootNavigator({}: Props) {
return (
<NavigationContainer>
<RootStack.Navigator screenOptions={{ headerShown: false }}>
{/* 앱 진입 시점: 항상 Main부터 */}
<RootStack.Screen name="Main" component={MainNavigator} />
{/* 필요할 때만 navigate 해서 여는 로그인 플로우 */}
<RootStack.Screen
name="Auth"
component={AuthNavigator}
options={{
gestureEnabled: true,
fullScreenGestureEnabled: true,
animation: "slide_from_right",
}}
/>
</RootStack.Navigator>
</NavigationContainer>
);
}
RootNavigator에서 MainNavigator를 렌더하고 MainNavigator안에서 navigationGuard를 만들어 특정 상황에서 인증이 필요하다면 AuthNavigator로 이동시켜주었다.
AuthNavigator안에서 로그인, 회원가입, 소셜로그인 등의 처리가 이루어졌다.
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import ChatDetailScreen from "../screens/Chat/ChatDetailScreen";
import EventDetailScreen from "../screens/Event/EventDetailScreen";
import ProfileEditScreen from "../screens/Profile/ProfileEditScreen";
import TabNavigator from "./TabNavigator";
import AddPhotoTicketScreen from "app/screens/Event/AddPhotoTicketScreen";
import ApplicantInfoScreen from "app/screens/Event/ApplicantInfoScreen";
import EventApplyScreen from "app/screens/Event/EventApplyScreen";
import TicketScreen from "app/screens/Event/TicketScreen";
import ProfileSettingScreen from "app/screens/Profile/ProfileSettingScreen";
import {
ChatStackParamList,
EventStackParamList,
ProfileStackParamList,
} from "app/types/navigation";
type MainStackParamList = EventStackParamList &
ProfileStackParamList &
ChatStackParamList & {
MainTabs: undefined;
};
const Stack = createNativeStackNavigator<MainStackParamList>();
export default function MainNavigator() {
return (
<Stack.Navigator
screenOptions={{
headerShown: false,
gestureEnabled: true,
fullScreenGestureEnabled: true,
animation: "slide_from_right",
}}
initialRouteName="MainTabs"
>
{/* 1) 앱 진입 후 첫 화면 → TabNavigator */}
<Stack.Screen name="MainTabs" component={TabNavigator} />
{/* 2) 탭 아래 상세 화면들 (탭 안 보이는 스크린들) */}
{/* chat */}
<Stack.Screen name="ChatDetail" component={ChatDetailScreen} />
{/* event */}
<Stack.Screen name="EventDetail" component={EventDetailScreen} />
<Stack.Screen name="EventApply" component={EventApplyScreen} />
<Stack.Screen name="ApplicantInfo" component={ApplicantInfoScreen} />
<Stack.Screen
name="Ticket"
component={TicketScreen}
options={{
gestureEnabled: false,
fullScreenGestureEnabled: false,
}}
/>
<Stack.Screen name="AddPhotoTicket" component={AddPhotoTicketScreen} />
{/* profile */}
<Stack.Screen name="ProfileSetting" component={ProfileSettingScreen} />
<Stack.Screen name="ProfileEdit" component={ProfileEditScreen} />
</Stack.Navigator>
);
}
MainNavigator에서는 위처럼 TabNavigator를 init으로 렌더한다. TabNavigator에서 각 탭별로 스크린을 연결하고 initialScreen을 주어 진입지점을 처리할 수 있었다. 그 이후 추가로 스크린이 열려야 하는 경우를 카테고리별로 나눠서 지정해주었다.
page라우팅에 익숙해져 개념이 생소하긴 했지만 보다보니 금방 적응이 되어 다행이다,,
앱이 고도화되면 추가로 Navigator를 의도에 맞게 생성해나가는 방식으로 접근해야 할 것 같다.
'React-Native' 카테고리의 다른 글
| [RN] Expo eas build에서 네트워크 요청이 안되는 현상 (0) | 2025.12.10 |
|---|---|
| [RN] React-Native 안전하게 인증 처리하기 (0) | 2025.12.09 |
| [RN] Expo 54버전, 안드로이드에서 GoogleMaps API Key 인식 못 하던 이슈 (0) | 2025.11.26 |
| [RN] 메모리 누수로 인한 IOS 웹뷰 인스턴스 강제종료 (feat. 가비지 컬렉션) (0) | 2025.05.15 |
| [React Native] React Navigation (0) | 2023.07.19 |