React Navigation은 React Native에서 가장 널리 사용되는 네비게이션 라이브러리입니다.

모바일 앱은 여러 화면으로 구성됩니다. 웹에서 URL 기반 라우팅을 하듯, React Native에서는 React Navigation 으로 화면 전환을 관리합니다.


설치

BASH
# 핵심 패키지
npm install @react-navigation/native

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

# 필수 의존성 (CLI)
npm install react-native-screens react-native-safe-area-context
cd ios && pod install

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

# Bottom Tab Navigator
npm install @react-navigation/bottom-tabs

# Drawer Navigator
npm install @react-navigation/drawer

Stack Navigator — 화면 쌓기

웹의 페이지 이동과 가장 유사한 패턴입니다. 새 화면이 위에 쌓이고, 뒤로 가면 제거됩니다.

TSX
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { View, Text, Pressable, StyleSheet } from 'react-native';

// 타입 정의 — 화면별 파라미터
type RootStackParamList = {
  Home: undefined;
  Detail: { id: number; title: string };
  Settings: undefined;
};

const Stack = createNativeStackNavigator<RootStackParamList>();

// 앱 진입점
export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen
          name="Home"
          component={HomeScreen}
          options={{ title: '' }}
        />
        <Stack.Screen
          name="Detail"
          component={DetailScreen}
          options={{ title: '상세' }}
        />
        <Stack.Screen
          name="Settings"
          component={SettingsScreen}
          options={{ title: '설정' }}
        />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

화면 이동과 파라미터 전달

TSX
import { NativeStackScreenProps } from '@react-navigation/native-stack';

type HomeProps = NativeStackScreenProps<RootStackParamList, 'Home'>;

function HomeScreen({ navigation }: HomeProps) {
  return (
    <View style={styles.container}>
      <Pressable
        style={styles.button}
        // 파라미터와 함께 화면 이동
        onPress={() => navigation.navigate('Detail', {
          id: 1,
          title: '첫 번째 아이템',
        })}
      >
        <Text style={styles.buttonText}>상세 화면으로</Text>
      </Pressable>

      {/* push — 같은 화면도 중복 쌓기 가능 */}
      <Pressable onPress={() => navigation.push('Detail', { id: 2, title: '두 번째' })}>
        <Text>Push로 이동</Text>
      </Pressable>
    </View>
  );
}

type DetailProps = NativeStackScreenProps<RootStackParamList, 'Detail'>;

function DetailScreen({ route, navigation }: DetailProps) {
  // 전달받은 파라미터
  const { id, title } = route.params;

  return (
    <View style={styles.container}>
      <Text>ID: {id}</Text>
      <Text>제목: {title}</Text>

      {/* 뒤로 가기 */}
      <Pressable onPress={() => navigation.goBack()}>
        <Text>뒤로</Text>
      </Pressable>

      {/* 특정 화면으로 돌아가기 */}
      <Pressable onPress={() => navigation.popToTop()}>
        <Text>최상위로</Text>
      </Pressable>
    </View>
  );
}

navigatepush의 차이가 면접에서 나올 수 있습니다. navigate는 이미 스택에 있는 화면이면 그 화면으로 이동하고, push는 항상 새 화면을 쌓습니다.


Bottom Tab Navigator

TSX
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

type TabParamList = {
  HomeTab: undefined;
  SearchTab: undefined;
  ProfileTab: undefined;
};

const Tab = createBottomTabNavigator<TabParamList>();

function TabNavigator() {
  return (
    <Tab.Navigator
      screenOptions={{
        tabBarActiveTintColor: '#007AFF',
        tabBarInactiveTintColor: '#999',
        tabBarStyle: {
          height: 60,
          paddingBottom: 8,
        },
      }}
    >
      <Tab.Screen
        name="HomeTab"
        component={HomeScreen}
        options={{
          title: '',
          tabBarIcon: ({ color, size }) => (
            <Text style={{ color, fontSize: size }}>🏠</Text>
          ),
          tabBarBadge: 3, // 배지 표시
        }}
      />
      <Tab.Screen
        name="SearchTab"
        component={SearchScreen}
        options={{
          title: '검색',
          tabBarIcon: ({ color, size }) => (
            <Text style={{ color, fontSize: size }}>🔍</Text>
          ),
        }}
      />
      <Tab.Screen
        name="ProfileTab"
        component={ProfileScreen}
        options={{
          title: '프로필',
          tabBarIcon: ({ color, size }) => (
            <Text style={{ color, fontSize: size }}>👤</Text>
          ),
        }}
      />
    </Tab.Navigator>
  );
}

네비게이터 중첩

실제 앱은 Tab 안에 Stack이 있는 형태가 일반적입니다.

TSX
// Tab + Stack 중첩 구조
function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        {/* 메인 탭 */}
        <Stack.Screen
          name="MainTabs"
          component={TabNavigator}
          options={{ headerShown: false }}
        />
        {/* 탭 위에 쌓이는 모달/상세 화면 */}
        <Stack.Screen name="Detail" component={DetailScreen} />
        <Stack.Screen
          name="Modal"
          component={ModalScreen}
          options={{ presentation: 'modal' }}
        />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

헤더 커스터마이징

TSX
<Stack.Screen
  name="Home"
  component={HomeScreen}
  options={{
    title: '홈',
    headerStyle: {
      backgroundColor: '#007AFF',
    },
    headerTintColor: 'white',
    headerTitleStyle: {
      fontWeight: 'bold',
    },
    // 커스텀 헤더 버튼
    headerRight: () => (
      <Pressable onPress={() => alert('설정')}>
        <Text style={{ color: 'white' }}>설정</Text>
      </Pressable>
    ),
    // 헤더 숨기기
    // headerShown: false,
  }}
/>

동적 헤더 옵션

TSX
function DetailScreen({ navigation, route }: DetailProps) {
  // 화면 진입 후 헤더 동적 변경
  React.useLayoutEffect(() => {
    navigation.setOptions({
      title: route.params.title,
      headerRight: () => (
        <Pressable onPress={handleShare}>
          <Text>공유</Text>
        </Pressable>
      ),
    });
  }, [navigation, route.params.title]);

  return <View />;
}

화면 간 데이터 전달 정리

TSX
// 1. params로 전달 (순방향)
navigation.navigate('Detail', { id: 1 });
// 받기: route.params.id

// 2. 콜백으로 결과 받기 (역방향)
// 화면 A
navigation.navigate('Picker', {
  onSelect: (value: string) => setValue(value),
});
// 화면 B
route.params.onSelect('선택된 값');
navigation.goBack();

// 3. 전역 상태 사용 (권장)
// Context API, Zustand, Redux 등으로 관리

네비게이션 이벤트

TSX
import { useFocusEffect } from '@react-navigation/native';
import { useCallback } from 'react';

function ProfileScreen() {
  // 화면에 포커스될 때마다 실행 (탭 전환 시 유용)
  useFocusEffect(
    useCallback(() => {
      console.log('화면 포커스됨 — 데이터 새로고침');

      return () => {
        console.log('화면 벗어남 — 정리 작업');
      };
    }, [])
  );

  return <View />;
}

정리

  • Stack: 화면을 쌓고 뒤로 가는 기본 네비게이션
  • Bottom Tab: 하단 탭으로 주요 섹션 전환
  • Drawer: 사이드 메뉴
  • 실제 앱에서는 Tab 안에 Stack을 중첩 하는 패턴이 가장 흔합니다
  • TypeScript로 ParamList 타입을 정의하면 화면 이동 시 타입 안전성을 확보할 수 있습니다
  • navigate는 기존 화면으로 이동, push는 항상 새 화면 생성 — 이 차이를 기억하세요
댓글 로딩 중...