React Navigation 기초 (@react-navigation)

개요

React Navigation은 React Native에서 화면 이동을 처리하는 표준 라이브러리입니다. 웹의 React Router와 비슷한 역할을 합니다.


설치

# 코어 패키지
npm install @react-navigation/native

# Stack Navigator
npm install @react-navigation/native-stack

# Expo 필수 의존성
npx expo install react-native-screens react-native-safe-area-context

기본 설정

1. NavigationContainer 감싸기

앱의 최상위에서 NavigationContainer로 감싸야 합니다.

// App.tsx
import { NavigationContainer } from "@react-navigation/native";
import RootNavigator from "./src/navigation/RootNavigator";

export default function App() {
  return (
    <NavigationContainer>
      <RootNavigator />
    </NavigationContainer>
  );
}

2. Stack Navigator 생성

// src/navigation/RootNavigator.tsx
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import HomeScreen from "../screens/HomeScreen";
import DetailScreen from "../screens/DetailScreen";

// 1. 타입 정의 (TypeScript)
export type RootStackParamList = {
  Home: undefined;                    // 파라미터 없음
  Detail: { itemId: number };         // 파라미터 있음
  Profile: { userId: string } | undefined;  // 파라미터 선택적
};

// 2. Navigator 생성
const Stack = createNativeStackNavigator<RootStackParamList>();

const RootNavigator = () => {
  return (
    <Stack.Navigator
      initialRouteName="Home"  // 초기 화면
      screenOptions={{
        headerShown: false,    // 기본 헤더 숨기기
      }}
    >
      <Stack.Screen name="Home" component={HomeScreen} />
      <Stack.Screen name="Detail" component={DetailScreen} />
    </Stack.Navigator>
  );
};

export default RootNavigator;

네비게이션 메서드

1. navigate() - 화면 이동

import { useNavigation } from "@react-navigation/native";
import type { NativeStackNavigationProp } from "@react-navigation/native-stack";
import type { RootStackParamList } from "../navigation/RootNavigator";

type NavigationProp = NativeStackNavigationProp<RootStackParamList, "Home">;

const HomeScreen = () => {
  const navigation = useNavigation<NavigationProp>();

  const goToDetail = () => {
    // 파라미터 없이 이동
    navigation.navigate("Profile");
    
    // 파라미터와 함께 이동
    navigation.navigate("Detail", { itemId: 123 });
  };

  return (
    <Button title="상세 보기" onPress={goToDetail} />
  );
};

2. goBack() - 뒤로가기

const DetailScreen = () => {
  const navigation = useNavigation();

  return (
    <Button title="뒤로" onPress={() => navigation.goBack()} />
  );
};

3. CommonActions.reset() - 스택 초기화

뒤로가기를 방지하고 싶을 때 사용합니다. (로그인 후, 회원가입 완료 후 등)

import { CommonActions } from "@react-navigation/native";

const LoginScreen = () => {
  const navigation = useNavigation();

  const handleLoginSuccess = () => {
    // 스택을 완전히 초기화하고 Home으로 이동
    // 뒤로가기 불가능
    navigation.dispatch(
      CommonActions.reset({
        index: 0,
        routes: [{ name: "Home" }],
      })
    );
  };

  return (
    <Button title="로그인" onPress={handleLoginSuccess} />
  );
};

메서드 동작 뒤로가기 사용 예시
navigate() 스택에 화면 추가 가능 일반적인 화면 이동
reset() 스택 완전 초기화 불가능 로그인/회원가입 완료 후

파라미터 받기

useRoute 사용

import { useRoute } from "@react-navigation/native";
import type { RouteProp } from "@react-navigation/native";
import type { RootStackParamList } from "../navigation/RootNavigator";

type DetailRouteProp = RouteProp<RootStackParamList, "Detail">;

const DetailScreen = () => {
  const route = useRoute<DetailRouteProp>();
  const { itemId } = route.params;

  return (
    <Text>아이템 ID: {itemId}</Text>
  );
};

조건부 초기 화면 결정

로그인 상태에 따라 다른 화면을 보여주는 패턴입니다.

// src/navigation/RootNavigator.tsx
import { useAuthStore } from "../stores/authStore";

const RootNavigator = () => {
  const isLoggedIn = useAuthStore((state) => state.isLoggedIn);
  const userType = useAuthStore((state) => state.userInfo?.userType);

  // 초기 화면 결정
  const getInitialRoute = () => {
    if (!isLoggedIn) {
      return "Welcome";  // 로그인 필요
    }
    if (userType === "WORKER") {
      return "WorkerHome";
    }
    return "EmployerHome";
  };

  return (
    <Stack.Navigator initialRouteName={getInitialRoute()}>
      <Stack.Screen name="Welcome" component={WelcomeScreen} />
      <Stack.Screen name="WorkerHome" component={WorkerHomeScreen} />
      <Stack.Screen name="EmployerHome" component={EmployerHomeScreen} />
    </Stack.Navigator>
  );
};

중첩 Navigator (Nested Navigation)

회원가입처럼 여러 단계로 나뉘어진 플로우를 별도 Navigator로 분리할 수 있습니다.

// src/navigation/SignUpNavigator.tsx
export type SignUpStackParamList = {
  Step1UserType: undefined;
  Step2Profile: undefined;
  Step3BasicInfo: undefined;
  Step4Alarm: undefined;
  Step5Complete: undefined;
};

const Stack = createNativeStackNavigator<SignUpStackParamList>();

const SignUpNavigator = () => {
  return (
    <Stack.Navigator
      initialRouteName="Step1UserType"
      screenOptions={{ headerShown: false }}
    >
      <Stack.Screen name="Step1UserType" component={Step1Screen} />
      <Stack.Screen name="Step2Profile" component={Step2Screen} />
      <Stack.Screen name="Step3BasicInfo" component={Step3Screen} />
      <Stack.Screen name="Step4Alarm" component={Step4Screen} />
      <Stack.Screen name="Step5Complete" component={Step5Screen} />
    </Stack.Navigator>
  );
};
// RootNavigator에서 SignUpNavigator 사용
<Stack.Screen name="SignUp" component={SignUpNavigator} />

TypeScript 타입 정리

타입 설명 사용처
ParamList 화면별 파라미터 정의 Navigator 생성 시
NativeStackNavigationProp navigation 객체 타입 useNavigation 훅
RouteProp route 객체 타입 useRoute 훅
// 타입 정의 예시
import type { NativeStackNavigationProp } from "@react-navigation/native-stack";
import type { RouteProp } from "@react-navigation/native";

// ParamList 정의
export type RootStackParamList = {
  Home: undefined;
  Detail: { itemId: number };
};

// Navigation 타입 (특정 화면에서 사용)
type HomeNavigationProp = NativeStackNavigationProp<RootStackParamList, "Home">;

// Route 타입 (파라미터 받는 화면에서 사용)
type DetailRouteProp = RouteProp<RootStackParamList, "Detail">;

React Router (웹) vs React Navigation (모바일) 비교

항목 React Router (웹) React Navigation (RN)
라우팅 URL 기반 스택 기반
이동 , navigate() navigation.navigate()
뒤로가기 브라우저 뒤로가기 navigation.goBack()
파라미터 URL params, state route.params
스택 초기화 replace() CommonActions.reset()