Computer >> 컴퓨터 >  >> 스마트폰 >> iPhone

React Navigation 5로 React Native 네비게이션 완벽하게 다루기

React Native에서 네비게이션을 이야기할 때 가장 먼저 떠오르는 라이브러리가 바로 react-navigation입니다.

저는 이 라이브러리의 열렬한 팬으로, React Native에서 네비게이션을 처리할 때 항상 첫 번째 선택지로 삼습니다. 훌륭하고 사용하기 쉬운 API를 갖추고 있을 뿐만 아니라 커스터마이징 자유도가 매우 높기 때문입니다.

이 글을 쓰게 된 이유는 버전 5가 드디어 베타 단계를 거쳐 정식(stable) 버전으로 출시되었기 때문입니다. 여러 기능 변화와 함께 라우트를 선언하는 더 간단하고 색다른 방식의 새로운 API 디자인이 도입되었습니다.

이번 글에서는 새롭게 바뀐 API들을 하나씩 살펴보고, 실제 애플리케이션에서 활용하는 방법까지 알아보겠습니다.

설치 방법

react-navigation의 설치 방식은 이전 버전(4.x 이하)과 비교해 조금 달라졌습니다.

// 4.x 이하 버전
yarn add react-navigation

react-navigation 5의 설치는 다음과 같습니다.

// yarn
yarn add @react-navigation/native
// npm
npm install @react-navigation/native

최신 버전의 react-navigation은 애니메이션과 화면 전환 처리를 위해 react-native-gesture-handler와 같은 서드파티 라이브러리를 폭넓게 활용합니다. 따라서 아래 라이브러리들도 반드시 함께 설치해야 합니다.

// yarn
yarn add react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view
// npm
npm install react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view

동적 스크린(Dynamic Screens)

새로운 API는 라우트 초기화 과정에 '동적' 요소를 도입했습니다. 이전에는 정적(static) 방식으로, 설정 파일 안에 라우트를 미리 정의해 두어야 했습니다.

// @flow
import React from "react";

import { createAppContainer, createSwitchNavigator } from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";

/** ---------Screens----------- */
import HomeScreen from "../Containers/HomeScreen";
import ProfileScreen from "../Containers/ProfileScreen";
import LoginScreen from "../Containers/LoginScreen";

const StackNavigator = createStackNavigator(
  {
    initialRouteName: "Home"
  },
  {
    Home: {
      screen: HomeScreen
    },
    Login: {
      screen: LoginScreen,
      headerMode: "none",
    },
    Profile: {
      screen: ProfileScreen
    }
  }
);

export default createAppContainer(StackNavigator);

반면 새로운 API는 동적 컴포넌트 방식을 제공하여 네비게이션을 훨씬 더 유연하게 구성할 수 있습니다.
새로운 방식으로 라우트를 선언하면 아래와 같이 작성하게 됩니다.

import React from "react"
import { SafeAreaView, StyleSheet, View, Text, StatusBar } from "react-native"

import { NavigationContainer } from "@react-navigation/native"
import { createStackNavigator } from "@react-navigation/stack"

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView style={styles.containerStyle}>
        <AppNavigation />
      </SafeAreaView>
    </>
  )
}
const Stack = createStackNavigator()
const AppNavigation = () => {
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="home">
        <Stack.Screen name="home" component={HomeScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  )
}
const HomeScreen = () => {
  return (
    <View style={styles.containerStyle}>
      <Text style={styles.title}>Home Screen</Text>
    </View>
  )
}

React Navigation 5로 React Native 네비게이션 완벽하게 다루기

이 새로운 방식은 동적이면서도 사용법이 훨씬 간단하고, 어딘가 react-router의 API와 비슷한 느낌마저 줍니다.

동적 옵션(Dynamic Options)

이 기능은 오랫동안 커뮤니티에서 가장 많이 요청받던 기능입니다. 저 역시 기존의 정적 방식 때문에 늘 불편함을 겪었고, 네비게이션 동작을 동적으로 변경하는 일이 무척 까다로웠습니다.

기존 방식 (4.x 이하)

구버전의 react-navigation에서는 옵션을 정적으로 정의해야 했고, 이를 런타임에 동적으로 변경할 방법이 없었습니다.

  static navigationOptions = {
    title: "Sign In",
    header: null,
    mode: "modal",
    headerMode: "none"
  };

새로운 방식 (버전 5)

react-navigation 5는 무척 간단한 동적 방식을 제공합니다. 이제 props만으로 어떤 화면에든 옵션을 자유롭게 지정할 수 있습니다.

const AppNavigation = ({}) => {
  let auth = {
    authenticated: true,
    user: {
      email: "user@mail.com",
      username: "John",
    },
  }
  let ProfileScreenTitle = auth.authenticated ? auth.user.username : "Profile"
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen
          name="Profile"
          component={ProfileScreen}
          options={{
            title: ProfileScreenTitle,
            headerTintColor: "#4aa3ba",
            headerStyle: {
              backgroundColor: darkModeOn ? "#000" : "#fff",
            },
          }}
        />
        <Stack.Screen name="About" component={AboutScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  )
}

React Navigation 5로 React Native 네비게이션 완벽하게 다루기

동적 옵션을 활용하면 인증 상태에 따라 화면 제목을 바꿀 수 있습니다. 예를 들어 사용자가 로그인한 상태라면 화면 제목을 해당 사용자의 닉네임으로 설정하거나, 헤더의 배경색을 상황에 맞게 변경할 수도 있습니다.

이 기능은 특히 동적으로 테마를 교체하거나 앱에 다크 모드를 구현하려는 경우에 매우 유용합니다.

훅(Hooks)

개인적으로 가장 마음에 드는 기능이며, 개발 시간을 크게 절약해 줍니다. 새로운 API는 특정 동작을 손쉽게 수행할 수 있는 커스텀 훅들을 도입했습니다.

이전 버전에서는, 예를 들어 현재 활성화된 화면의 이름(routeName)을 가져오려면 다음과 같은 헬퍼 함수를 직접 만들어야 했습니다.

export function getCurrentRouteName(): string | null {
  const tag = "[getCurrentRouteNameSync] "
  const navState = getStore().getState().nav
  const currentRoute = getActiveRouteState(navState)
  console.log(tag + " currentRoute > ", currentRoute)
  return currentRoute && currentRoute.routeName ? currentRoute.routeName : null
}

훅(Hooks) API는 이런 번거로운 작업을 없애 주고, 단 한 줄의 훅으로 네비게이션 API에 접근할 수 있게 해 줍니다.

이제 useRoute 훅으로 RouteName을 간편하게 가져올 수 있습니다.

import { useRoute } from "@react-navigation/native"
const AboutScreen = ({ navigation }) => {
  const route = useRoute()
  return (
    <View
      style={{
        justifyContent: "space-around",
        flex: 1,
        alignItems: "center",
      }}
    >
      {/*    여기서 RouteName을 표시합니다 */}
      <Text style={styles.title}>{route.name}</Text>
    </View>
  )
}

useNavigationState 훅으로도 같은 작업이 가능합니다. 이 훅은 네비게이션 상태 전체에 접근할 수 있게 해 줍니다.

const navigationState = useNavigationState(state => state)
let index = navigationState.index
let routes = navigationState.routes.length
console.log(index)
console.log(routes)

react-navigation은 그 외에도 다양한 훅을 제공합니다. 대표적인 예는 다음과 같습니다.

  • useFocusEffect : 화면이 로드되어 포커스될 때 부수 효과(side effect)를 실행하는 훅
  • useLinking : 딥링킹(deep linking)을 처리하는 훅

이 훅들은 공식 문서를 통해 직접 확인해 보시길 강력히 추천합니다.

마치며

새로운 react-navigation API는 분명히 정적 방식에서 동적 방식으로 전환하고 있습니다. React Native에서 네비게이션을 다루는 방식을 완전히 바꿀 수 있는 훌륭한 방향입니다. 동적 라우트는 react-navigation 사용자들이 오랫동안 요청해 온 기능이었고, 이 새로운 방식은 더 나은 사용자 네비게이션 경험을 만드는 데 큰 도움이 될 것입니다.

읽어주셔서 감사합니다. 원문은 saidhayani.com에 게시되었습니다.