React & React Native/라이브러리 활용

[RN] React Native Stack Navigator과 하단 네비게이션(Bottom Tab Navigator) 함께 사용하기 : Nesting Navigators

adjh54 2023. 7. 5. 17:50
반응형
해당 글에서는 Stack Navigator와 Bottom Tab Navigator를 함께 사용하는 Nesting Navigators를 구성하는 방법에 대해서 공유합니다.




 

1) Stack Navigator


💡 Stack Navigator

- ‘스택 형태’로 화면 위에 새로운 화면을 쌓아서 탐색을 하는 내비게이션 컴포넌트를 의미합니다.


- 스택 형태로 쌓아두기에 이전 화면으로 되돌아갈 수 있으며 탐색 히스토리를 유지하는 특징을 가지고 있습니다. 그렇기에 주로 탐색이 많은 애플리케이션에 적합합니다.
- 예를 들어, A 화면에서 버튼을 누르면 B 화면으로 이동하고, B 화면에서 다시 버튼을 누르면 A 화면으로 돌아오는 경우에 사용할 수 있습니다. 기본적으로 스택 내비게이터는 iOS에서는 새 화면으로 이동 시 오른쪽에서 슬라이드 되고 Andriod에서는 OS 기본 애니메이션이 사용됩니다. (* 해당 애니메이션을 사용자의 선택으로 정의할 수 있음)
[참고] react-native-navigation에 대해 궁금하시면 도움이 됩니다.
 

[RN] 페이지 이동 관리 이해하고 설정하기: react-native-navigation

해당 글에서는 React-native에서 페이지 별 이동을 위한 Navigation 구성에 대해 이해를 돕기 위해 작성한 글입니다. 1) React Native Navigation 이란? 💡 React Native Navigation란? - React Native 애플리케이션의 ‘

adjh54.tistory.com

 

 

 

2) 하단 내비게이션(Bottom Tab Navigator/ Material Bottom Tabs Navigator)


💡 Bottom Tabs Navigator

- React Native에서 제공하는 내비게이션 라이브러리 중 하나입니다. 이 라이브러리를 사용하면 ‘하단에 위치한 탭 바’를 통해 ‘다른 화면으로 이동’하는 기능을 구현할 수 있습니다.

💡 Material Bottom Tabs Navigator


- 안드로이드 디자인 패턴 중 하나인 Material Design을 기반으로 한 React Native 라이브러리입니다. 이 라이브러리는 ‘하단 탭 내비게이션’을 간편하게 구현할 수 있도록 도와줍니다.

 

 

💡 [참고] Navigation 동작은 아래의 링크를 통해서 확인하시면 좀 더 이해하기가 쉽습니다.
 

React Navigation

 

reactnavigation.org

 

 

React Navigation

 

reactnavigation.org

 

 

1. Bottom Tabs Navigator과 Material Bottom Tabs Navigator 비교


비교 Bottom Tabs Navigator  Material Bottom Tabs Navigator
동작 플랫폼 iOS, Android Android
디자인 가이드 일반적인 UI/UX Material 디자인 가이드에 따른 UI/UX
사용자 정의 기능 다양한 옵션 제공 제한적인 사용자 정의 기능
아이콘 및 라벨 설정 가능 가능

 

 

 

2. Tab.Navigator의 screenOptions 옵션


💡 Tab.Navigator의 screenOptions 옵션

- customBottomTabNaviOptions 값으로 사용되는 속성들에 대한 옵션입니다.
<Tab.Navigator screenOptions={customBottomTabNaviOptions}>
속성 설명
title headerTitle 및 tabBarLabel의 대체 제목에 대한 속성
tabBarLabel - 탭 바에서 표시되는 탭의 제목 문자열 또는 { focused : boolean, color : string }를 받아 React.Node를 반환하는 함수.
- tabBarShowLabel를 숨기려면 정의하지 않으면 scene title이 사용됩니다.
tabBarShowLabel 탭 라벨을 표시할지 여부에 대한 속성 (기본값은 true입니다.)
tabBarLabelPosition - 라벨이 아이콘 아래에 표시되는지 옆에 표시되는지 여부에 대한 속성
- below-icon : 라벨이 아이콘 아래에 표시됨 (아이폰의 특징), beside-icon : 라벨이 아이콘 옆에 표시됨 (iPad의 특징).
- 기본적으로 기기 너비에 따라 위치가 자동으로 선택됩니다.
tabBarLabelStyle 탭 라벨의 스타일 객체
tabBarIcon { focused : boolean, color : string, size : number }를 받아 React.Node를 반환하는 함수. 탭 바에 표시됩니다.
tabBarIconStyle 탭 아이콘의 스타일 객체
tabBarBadge 탭 아이콘에 표시할 텍스트. 문자열 또는 숫자를 허용합니다.
tabBarBadgeStyle 탭 아이콘에있는 배지의 스타일. 여기에서 배경색이나 글꼴 색상을 지정할 수 있습니다.
tabBarAccessibilityLabel 탭 버튼에 대한 접근성 레이블. 사용자가 탭을 누르면 화면 판독기에서 읽습니다. 탭에 레이블이없는 경우 설정하는 것이 좋습니다.
tabBarTestID 테스트에서이 탭 버튼을 찾을 ID입니다.
tabBarButton 탭 바 버튼으로 렌더링 할 React 요소를 반환하는 함수. 아이콘과 레이블을 둘러싸는 것입니다. 기본적으로Pressable을 렌더링합니다.

tabBarActiveTintColor 활성 탭의 아이콘 및 레이블 색상
tabBarInactiveTintColor 비활성 탭의 아이콘 및 레이블 색상
tabBarActiveBackgroundColor 활성 탭의 배경색
tabBarInactiveBackgroundColor 비활성 탭의 배경색
tabBarHideOnKeyboard 키보드가 열릴 때 탭 바를 숨길지 여부. 기본값은 false입니다.
tabBarItemStyle 탭 항목 컨테이너의 스타일 개체
tabBarStyle 탭 바의 스타일 개체. 여기에서 배경색과 같은 스타일을 구성할 수 있습니다.

 

 

React Navigation

 

reactnavigation.org

 

 

 

3) Stack Navigator과 Bottom Tab Navigator 차이


💡 두 가지 Navigator의 경우 다른 탐색 방법입니다.

💡Stack Navigation은 화면 위에 새로운 화면을 쌓아서 탐색하는 방법입니다.

- 이전에 본 화면으로 돌아갈 수 있으며, 탐색 히스토리를 유지합니다. 이 방법은 주로 탐색이 많은 애플리케이션에 적합합니다.

💡 Bottom Tab Navigator는 화면 아래에 탭을 사용하여 탐색하는 방법입니다.
- 각 탭은 별도의 화면을 나타내며, 탭 간 전환을 위해 사용자가 탭을 클릭하거나 스와이프 할 수 있습니다. 이 방법은 탐색이 적은 애플리케이션에 적합합니다.
분류 Stack Navigator Bottom Tab Navigator
설명 화면 위에 새로운 화면을 쌓아서 탐색하는 방법 : 계층적 네비게이션 화면 아래에 탭을 사용하여 탐색하는 방법 : 평면적 네비게이션
화면전환 이전 페이지로 이동이 가능함 이전 페이지로 이동이 불가능함
적합한 유형 페이지 간의 탐색이 많은 애플리케이션에 적합 페이지간의 탐색이 적은 애플리케이션에 적합
React Navigation 버전 v1부터 v6까지 지원 v5부터 v6까지 지원

 

 

 

 

4) Stack Navigator + Bottom Tab Navigator 구현 : Nesting Navigators


💡 해당 부분에서는 이전에 구성한 StackNavigator와 ‘Bottom Tab Navigator’를 선택하여서 중첩된 내비게이터(Nesting Navigators)를 구현하는 부분입니다.

💡 이렇게 구현하는 이유는 하단 탭 Navigator 형태로 사용할 수도 있지만 로그인과 같이 아직 로그인이 안된 상태의 페이지 경우에는 하단의 탭이 필요 없기에 이를 위해서 사용됩니다.

 

 

💡 [참고] 공식사이트 Nesting Navigators
 

React Navigation

 

reactnavigation.org

 

 

1. Stack Navigator 구성


💡 기존의 StackNavigator는 아래의 링크를 확인하시면 구현할 수 있습니다.
 

[RN] 페이지 이동 관리 이해하고 설정하기: react-native-navigation

해당 글에서는 React-native에서 페이지 별 이동을 위한 Navigation 구성에 대해 이해를 돕기 위해 작성한 글입니다. 1) React Native Navigation 이란? 💡 React Native Navigation란? - React Native 애플리케이션의 ‘

adjh54.tistory.com

 

 

 

2. Bottom Tab Navigator 라이브러리 추가


# Bottom Tab Navigator 라이브러리 설치(yarn)
# npm i @react-navigation/bottom-tabs

# or

# Bottom Tab Navigator 라이브러리 설치(yarn)
$ yarn add @react-navigation/bottom-tabs

 

 

 

3. 구현하기


💡 ‘Stack Navigator’내의 ‘Bottom Tab Navigator’를 추가하는 형태로 구성합니다.

 

https://reactnavigation.org/docs/nesting-navigators/

 

 

3.1. App.tsx

💡 NavigationContainer내에 StackNavigator를 감싸줍니다.
import { NavigationContainer } from '@react-navigation/native';
import React from 'react';
import StackNavigator from 'screens/navigation/StackNavigator';

/**
 * 앱의 메인 화면
 */

const App = () => {
  return (
    <NavigationContainer>
      <StackNavigator />
    </NavigationContainer>
  )
}
export default App;

 

 

 

4. Stack Navigator 구성


💡 StackNavigator 파일 내에서는 하단 탭이 포함되지 않은 화면과 포함된 화면을 함께 불러옵니다.

- Stack.Screen으로 즉시 불러오는 경우는 하단의 탭을 포함하지 않는 경우로 출력이 됩니다.
- Stack.Screen으로  BottomTabNavigator 컴포넌트를 불러오는 경우는 하단의 탭을 포함하는 경우로 불러옵니다.
import React from 'react'
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator, StackNavigationOptions } from '@react-navigation/stack';
import { CommonType } from 'types/common/CommonType';
import TemplateMainScreen from 'screens/template/TemplateMainScreen';
import BottomTabNavigator from './BottomTabNavigator';
import { Image, StyleSheet, Text, TouchableOpacity, View } from 'react-native';

/**
 * StackNavigator를 이용하여서 앱에 대한 페이지 이동을 관리합니다.
*/
const StackNavigator = (appStateType: any) => {

    // StackNavigation을 이용하여 페이지를 관리하며 각각 RootStackPageList에서 페이지를 관리합니다
    const Stack = createStackNavigator<CommonType.RootStackPageList>();

    return (
        // TabBar의 UI는 BottomTabBar 화면에서 관리합니다.
        <Stack.Navigator initialRouteName='home'>
            {/* 메인 페이지 */}
            <Stack.Screen name="home">
                {(props) => <Home {...props} appState={appStateType.appState} />}
            </Stack.Screen>
            {/* 관리자 페이지 */}
            <Stack.Screen name="adminScreen" >
                {(props) => <AdminScreen {...props} appState={appStateType.appState} />}
            </Stack.Screen>
            {/*  Bottom Tab Navigation을 Stack 내에 추가합니다. */}
            <Stack.Screen
                name='BottomTabNavigator'
                component={BottomTabNavigator}
                options={{ headerShown: false }}
            />
        </Stack.Navigator>
    )
}
export default StackNavigator;

 

 

5. StackNavigation 액션 함수


💡 StackNavigation을 이용하여 페이지를 이동하고자 할 때 사용하는 액션 함수에 대해 확인해 봅니다.
메서드 설명 뒤로가기 가능 여부
navigate 지정된 화면으로 이동합니다. 가능
goBack 이전 화면으로 돌아갑니다. 가능
push 새로운 화면을 스택에 추가합니다. 가능
pop 현재 화면을 스택에서 제거합니다. 불가능
replace 현재 화면을 다른 화면으로 교체합니다. 불가능
reset 스택을 초기화하고 새로운 화면으로 이동합니다. 불가능

 

 

6. Bottom Tab Navigator 구성


6.1. BottomTabNavigator

💡 BottomTabNavigator 파일 내에서는 BottomTab을 포함시켜서 출력하는 화면들에 대해서 관리합니다.

- Tab.Navigator 내에 Tab.Screen으로 각각을 등록해 줍니다.
- 그리고 또한 Tab.Navigator 내에 tabBar 속성을 이용하여 모바일 상에 출력하는 UI를 관리합니다.

 

import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import React from 'react'
import AdminScreen from 'screens/admin/AdminScreen';
import { Home } from 'screens/Home';
import { CommonType } from 'types/common/CommonType';
import BottomTabBar from './BottomTab';

/**
 * Bottom TabBar를 사용하는 경우의 Navigation
 * @param appStateType 
 * @returns 
 */
const BottomTabNavigator = (appStateType: any) => {
    const Tab = createBottomTabNavigator<CommonType.RootStackPageList>();

    return (
        // TabBar의 UI는 BottomTabBar 화면에서 관리합니다.
        <Tab.Navigator tabBar={props => <BottomTabBar {...props} />} >
           {/* 탭1 컴포넌트 페이지 */}
            <Tab.Screen name="tab1" >
                {(props) => <Tab1 {...props} appState={appStateType.appState} />}
            </Tab.Screen>

            {/* 탭2 컴포넌트 페이지 */}
            <Tab.Screen name="tab2" >
                {(props) => <Tab2 {...props} appState={appStateType.appState} />}
            </Tab.Screen>

            {/* 탭3 컴포넌트 페이지 */}
            <Tab.Screen name="tab3" >
                {(props) => <Tab3 {...props} appState={appStateType.appState} />}
            </Tab.Screen>

            {/* 탭4 컴포넌트 페이지 */}
            <Tab.Screen name="tab4" >
                {(props) => <Tab4 {...props} appState={appStateType.appState} />}
            </Stack.Screen>

            {/* 탭5 컴포넌트 페이지 */}
            <Tab.Screen name="tab5" >
                {(props) => <Tab5 {...props} appState={appStateType.appState} />}
            </Tab.Screen>

        </Tab.Navigator>
    )
}
export default BottomTabNavigator;

 

 

 

6.2. BottomTabBar

💡 BottomTabBar 페이지에서는 Bottom Tab Bar의 UI를 구성하며 BottomTabNavigator에 등록된 페이지 정보를 통해서 onPress 함수가 실행될 때 페이지를 전환시켜 줍니다.
import { APP_STATUS, BOTTOM_TAB_MENU_CODE } from 'common/codes/CommonCode';
import React, { useState } from 'react';
import { GestureResponderEvent, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
/**
 * 하단의 탭 내비게이션 UI 관리 
 * @param param0 
 * @returns 
 */
const BottomTabBar = ({ state, navigation }) => {

    const bottomMenuText = ["TAB1", "TAB2", "TAB3", "TAB4", "TAB5"]

    const [isFocused, setIsFocused] = useState(false);

    /**
     * 탭 버튼을 눌렀을 때 페이지 이동하기 
     * @param e 
     * @param index 
     */
    const pressBottomTab = (e: GestureResponderEvent, index: number) => {
        // index 별로 페이지를 등록하여서 즉시 페이지 이동을 합니다.
        navigation.navigate({ name: BOTTOM_TAB_MENU_CODE[index], merge: true });
    };

    /**
     * 탭 버튼을 길게 눌렀을 때 처리 
     */
    const longPressBottomTab = () => {

    }

    return (
        <View style={styles.container}>
            {
                bottomMenuText.map((menuText, index) =>
                    <TouchableOpacity
                        key={`menuKey-${index}`}
                        accessibilityRole="button"
                        onPress={(e) => pressBottomTab(e, index)}
                        onLongPress={longPressBottomTab}
                        style={styles.text}
                    >
                        <Text style={{ color: isFocused ? '#673ab7' : '#222' }}>
                            {menuText}
                        </Text>
                    </TouchableOpacity>
                )
            }
        </View>
    )
}

/**
 * [함수] 기본 스타일 적용 함수
 */
const styles = StyleSheet.create({

    container: {
        flexDirection: 'row',
        borderStyle: "solid",
        borderWidth: 1,
        borderColor: "black",
    },
    text: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
        height: 60
    },
})

export default BottomTabBar;

 

 

6.3. CommonCode.ts

/**
 * Bottom Tap의 메뉴별 인덱스 별로 화면에 등록된 정보를 가져옵니다.
 */
export const BOTTOM_TAB_MENU_CODE = {
    0: 'tab1',
    1: 'tab2',
    2: 'tab3',
    3: 'tab4',
    4: 'tab5',
}

 

 

 

5) 참고 : Bottom Tab Navigator에서 탭 이동 시 새로고침 하는 방법


💡 Bottom Tab Navigator에서 탭 이동 시 새로고침을 하는 방법은 options={{ unmountOnBlur: true, }} 옵션을 추가하면 됩니다. 그러면 탭을 선택했을 때마다 옵션을 추가한 탭에서는 새로고침이 발생합니다.
<Tab.Navigator initialRouteName='home' tabBar={props => <BottomTabBar {...props} />} >
    {/* 메인 페이지 */}
    <Tab.Screen name="home" options={{ unmountOnBlur: true }}>
        {(props) => <Home {...props} appState={appStateType.appState} />}
    </Tab.Screen>
    {/* 관리자 페이지 */}
    <Tab.Screen name="adminScreen" options={{ unmountOnBlur: true }}>
        {(props) => <AdminScreen {...props} appState={appStateType.appState} />}
    </Tab.Screen>
</Tab.Navigator >

 

 

6) 참고: Bottom Tap Navigator를 여러 개 사용하는 방법


💡 Bottom Tab Navigator를 상황에 따라서 여러 개를 구성하여서 호출하는 방법입니다.

 

1. Stack Navigator 구성


💡 Stack Navigator내에 두 개의 Bottom Tap Navigator를 등록합니다.
 // Stack Navigator의 시작은 Bottom Tab Navigator의 Home 화면이기에 Default 값으로 지정합니다.
<Stack.Navigator screenOptions={customStackNavigationOptions} initialRouteName={"home"}>

    {/* Stack Navigator 내에 'Bottom Tab Navigator1'를 등록합니다. */}
    <Stack.Screen name="bottomTabNav1" component={BottomTabNavigator1} options={{ headerShown: false }} />

    {/* Stack Navigator 내에 'Bottom Tab Navigator2'를 등록합니다. */}
    <Stack.Screen name="bottomTabNav2" component={BottomTabNavigator2} options={{ headerShown: false }} />
</Stack.Navigator

 

 

2. BottomTabNav1 구성


💡 Bottom Tab Naviagator에서는 tabBar 속성으로 BottomTabBar1이라는 UI를 호출합니다.
<Tab.Navigator
    screenOptions={customBottomTabNaviOptions}
    tabBar={props => <BottomTabBar1 {...props} />} >

    {/* 메인 페이지 */}
    <Tab.Screen name="home" options={{ unmountOnBlur: true }}>
        {(props) => <Home {...props} appState={appStateType.appState} />}
    </Tab.Screen>

</Tab.Navigator >

 

 

 

3. BottomTabNav2 구성


💡 Bottom Tab Naviagator에서는 tabBar 속성으로 BottomTabBar2이라는 UI를 호출합니다.
<Tab.Navigator
    screenOptions={customBottomTabNaviOptions}
    tabBar={props => <BottomTabBar2 {...props} />} >

    {/* 메인 페이지 */}
    <Tab.Screen name="study" options={{ unmountOnBlur: true }}>
        {(props) => <StudyScreen {...props} appState={appStateType.appState} />}
    </Tab.Screen>

</Tab.Navigator >

 

 

 

4. 화면상 호출부


💡 화면상에서 페이지 이동을 위해서는 navigation.navigator를 이용하며, 각각 bottomTabNav1 -> home / bottomTabNav2-> Study로 호출을 하여서 페이지를 이동합니다.
// 1번 Bottom Tap Navigator에 등록되어있는 페이지로 이동합니다.
navigation.navigate('bottomTabNav1', {
    screen: 'home',
    params: { key: "12o3812390812390" },
});


// 2번 Bottom Tap Navigator에 등록되어있는 페이지로 이동합니다.
navigation.navigate('bottomTabNav2', {
    screen: 'study',
    params: { key: "369" },
});

 

 

React Navigation

 

reactnavigation.org

 

 

 

 

 

오늘도 감사합니다. 😀

 

 

 

반응형