NavigationContainer

박은정·2022년 8월 23일
1

리액트네이티브

목록 보기
10/27

원문출처

NavigationContainer는 앱 상태를 관리하고 최상위 네비게이터를 앱 환경에 연결하는 역할을 합니다.

Container는 플랫폼별 통합을 처리하고 다음과 같은 유용한 기능을 제공합니다.

1.linking prop과의 딥링크 통합
2. screen tracking, state persistence 등을 위해 state의 변경사항을 알립니다.
3. 리액트 네이티브의 BackHandler API를 사용해서 안드로이드에서 시스템 뒤로 버튼을 처리합니다.

import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

const Stack = createNativeStackNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>{/* ... */}</Stack.Navigator>
    </NavigationContainer>
  );
}

🔖 Ref

Container에 Ref를 연결해서 dispatch navigation 액션같은 다양한 helper메서드에 접근할 수 있습니다.

import { NavigationContainer, useNavigationContainerRef } from '@react-navigation/native';

function App() {
  const navigationRef = useNavigationContainerRef(); // You can also use a regular ref with `React.useRef()`

  return (
    <View style={{ flex: 1 }}>
      <Button onPress={() => navigationRef.navigate('Home')}>
        Go home
      </Button>
      <NavigationContainer ref={navigationRef}>{/* ... */}</NavigationContainer>
    </View>
  );
}

일반 ref 객체를 사용하는 경우 링크를 사용하는 것같은 일부 상황에서 ref가 처음에 null일 수 있습니다. ref가 초기화되었는지 확인하려면 onReady 콜백을 사용해서 네비게이션 컨테이너가 마운트되었을때 알림을 받을 수 있습니다.

ref에서의 메서드

ref객체에는 navigate, goBack 등과 같은 일반적인 navigation 메서드가 모두 포함됩니다. 자세한 내용은 CommonActions reference를 참고해주세요.

이 모든 메서드는 현재 포커스된 화면 안에서 호출된 것처럼 작동합니다.
이러한 작업을 처리하려면 네비게이터가 렌더링되어야 합니다.

resetRoot 메서드를 사용하면 navigation tree를 지정된 state 객체로 재설정할 수 있습니다.

navigationRef.resetRoot({
  index: 0,
  routes: [{ name: 'Profile' }],
});

reset 메서드와는 달리, resetRoot 메서드는 현재 포커스된 화면의 네비게이터 대신 루트 네비게이터에서 실행됩니다.

getRootState 메서드는 navigation tree의 모든 네비게이터에 대한 navigation state를 포함하는 navigation state 객체를 반환합니다.

const state = navigationRef.getRootState();

현재 렌더링된 네비게이터가 없는 경우 반환된 state 객체는 undefined가 됩니다.

getCurrentRoute 메서드는 전체 navigation tree에서 현재 포커스된 화면에 대한 route 객체를 반환합니다.

const options = navigationRef.getCurrentOptions();

현재 렌더링된 네비게이터가 없는 경우 반환된 options 객체는 undefined가 됩니다.

addListener 메서드를 사용해서 다음 이벤트를 들을 수 있습니다.

1. state

이 이벤트는 navigation tree의 navigator에서 navigation state가 변경될 때마다 트리거됩니다.

const unsubscribe = navigationRef.addListener('state', (e) => {
  // 루트 네비게이터의 navigation state 일부객체를 얻을 수 있다.
  console.log(e.data.state);

  // 아니면 getRootState()메서드를 사용해서 전체 state 객체를 가져올 수도 있습니다
  console.log(navigationRef.getRootState());
});

addListener는 onStateChange메서드와 유사합니다.
유일한 차이점은 e.data.state 객체가 항상 전체 state 객체를 포함하는 onStateChange의 state인자와 달리, addListener는 state 객체의 일부분만을 포함할 수 있다는 점입니다.

2. options

이 이벤트는 navigation tree에서 현재 포커스된 화면에 대한 옵션이 변경될 때마다 트리거됩니다.

const unsubscribe = navigationRef.addListener('options', (e) => {
  // 현재 포커스된 화면에 대한 새로운 options을 얻을 수 있습니다.
  console.log(e.data.options);
});

그 밖의 props를 보자면, 다음과 같습니다.

🔖 initialState

네비게이터의 initialState를 지정하는 props입니다.
이는 딥링크, 상태 지속성 등과 같은 것과 관련해서 유용합니다.

<NavigationContainer
  onStateChange={(state) => console.log('New state is', state)}
  initialState={initialState}
>
  {/* ... */}
</NavigationContainer>

사용자 지정 initialState 객체를 제공하면 링크구성이나 브라우저의 URL에서 가져온 초기 상태 객체를 재정의할 수 있습니다.
initialState 객체를 제공하려면 웹에 전달하지 않고 처리할 수 있는 딥링크가 있는지 확인해야 합니다.

const initialUrl = await Linking.getInitialURL();

if (Platform.OS !== 'web' && initialUrl == null) {
  // 딥링크가 없고 웹이 아닐때만 state 리스토어(상태복원)한다.
  
}

🔖 onStateChange

참고

네비게이터의 state 객체가 내부객체이며 보조 릴리스에서 변경될 수 있습니다.
실제로 필요한 경우가 아니라면 index 및 route를 제외한 navigation state 객체의 속성을 사용하지 마세요.
state 객체의 구조에 의존하지 않고서는 구현할 수 없는 일부 기능이 있는경우 issue를 열어주세요.

navigation state가 변경될 때마다 호출되는 함수입니다. 새로운 navigation state를 인수로 수신합니다. 포커스된 화면을 추적하고 navigation state를 유지할 때 사용할 수 있습니다.

🔖 onReady

navigationContainer와 모든 하위 컨테이너가 처음으로 마운트를 마친 뒤 호출되는 함수입니다.

  • ref를 사용할 수 있는지 확인합니다. 자세한 내용은 ref 초기화 관련 문서를 참조하세요.
  • native splash screen 숨기기

🔖 onUnhandledAction

네비게이터가 네비게이션 동작을 처리하지 않을 때 호출되는 함수입니다.
기본적으로 리액트 네이게이션은 작업이 처리되지 않은 경우 개발 전용 오류 메시지를 표시합니다. 사용자 지정 기능을 제공해서 기본 동작을 재정의할 수 있습니다.

🔖 linking

딥링크, 브라우저 URL 지원 등에 사용되는 링크 통합 구성

import { NavigationContainer } from '@react-navigation/native';

function App() {
  const linking = {
    prefixes: ['https://mychat.com', 'mychat://'],
    config: {
      screens: {
        Home: 'feed/:sort',
      },
    },
  };

  return (
    <NavigationContainer linking={linking} fallback={<Text>Loading...</Text>}>
      {/* content */}
    </NavigationContainer>
  );
}

딥 링크 및 URL 통합을 구성하는 방법에 대한 자세한 내용은 링크 구성 안내서를 참조하세요.

Options

linking.prefixes

처리할 URL접두사입니다. 사용자지정 구성표와 범용 링크를 지원하기 위해 여러 개의 접두사를 제공할 수 있습니다.
이러한 접두사와 일치하는 URL만 처리됩니다. 구문 분석하기 전에 URL에서 접두사가 제거됩니다.

이는, iOS와 안드로이드에서만 지원됩니다.

<NavigationContainer
  linking={{
    prefixes: ['https://mychat.com', 'mychat://'],
    config: {
      screens: {
        Chat: 'feed/:sort',
      },
    },
  }}
>
  {/* content */}
</NavigationContainer>

linking.config

path를 어떻게 파싱할지 세부적으로 조정할 수 있도록 구성합니다. config객체는 앱의 네비게이터 구조를 나타내야 합니다.

예를들어, Home화면 안에 Catalog화면이 있고 이 화면이 item/:id 패턴을 처리하도록 하려면 아래와 같이 작성하면 됩니다.

// object type
{
  screens: {
    Home: {
      screens: {
        Catalog: {
          path: 'item/:id',
          parse: {
            id: Number,
          },
        },
      },
    },
  }
}

파싱을 위한 옵션은 객체나 문자열 모두 가능합니다.

// string type
{
  screens: {
    Catalog: 'item/:id',
  }
}

문자열로 지정하면 path 옵션을 제공하는 것과 동일합니다.

path 옵션은 path에 대해 일치시킬 패턴입니다. :로 시작하는 모든 segment는 동일한 이름의 파라미터로 인식됩니다.
예를들어 item/42{name: 'item', params: {id:42}}로 분석됩니다.

initialRouteName 옵션은 config 등과 같은 navigation state에서 제공되어 전달된 path이름을 보장합니다.

{
  screens: {
    Home: {
      initialRouteName: 'Feed',
      screens: {
        Catalog: {
          path: 'item/:id',
          parse: {
            id: Number,
          },
        },
        Feed: 'feed',
      },
    },
  }
}

그리고 :/item/42 URL에서 state는 다음과 같습니다

{
  routes: [
    {
      name: 'Home',
      state: {
        index: 1,
        routes: [
          {
            name: 'Feed'
          },
          {
            name: 'Catalog',
            params: { id: 42 },
          },
        ],
      },
    },
  ],
}

파싱옵션은 매개변수를 어떻게 파싱할지 제어합니다. 여기서 분석할 매개변수의 이름과 매개변수에 대한 문자열 값을 가져와서 파싱된 값을 반환하는 함수를 제공할 수 있습니다.

{
  screens: {
    Catalog: {
      path: 'item/:id',
      parse: {
        id: id => parseInt(id, 10),
      },
    },
  }
}

매개변수를 구문분석하는 사용자 지정 함수가 제공되지 않으면 문자열로 파싱됩니다.

linking.enabled

linking통합을 사용하거나 사용하지 않도록 설정하는 옵션값입니다.
linking prop이 지정된 경우 기본값은 true입니다.

linking.getInitialURL

기본적으로 linking은 리액트 네이티브의 Linking API와 통합되며 Linking.getInitialURL() 메서드를 사용해서 딥링크를 지원합니다.
하지만 branch같은 다른 소스의 링크나 Firebase 등을 사용해서 알림을 푸시할 수도 있습니다.

초기 URL로 사용해야 할 링크를 반환할 수 있는 커스텀 getInitialURL 함수를 제공할 수 있습니다. getInitialURL 함수는 처리할 URL이 있어야 할 경우 문자열을 반환해야 하며, 그렇지 않으면 undefined를 반환해야 합니다.

예를 들어, 다음과 같은 작업을 수행해서 딥링크 및 파이어베이스 알림을 모두 처리할 수 있습니다.

<NavigationContainer
  linking={{
    prefixes: ['https://mychat.com', 'mychat://'],
    config: {
      screens: {
        Chat: 'feed/:sort',
      },
    },
    async getInitialURL() {
      // 딥링크에서 앱이 열렸는지 확인합니다
      const url = await Linking.getInitialURL();

      if (url != null) {
        return url;
      }

      // 초기 파이어베이스 알림이 있는지 확인합니다
      const message = await messaging().getInitialNotification();

      // 화면에 해당하는 알림에서 url속성을 가져옵니다
      // 이 속성을 보낼 때 알림 payload를 설정해야 합니다
      return message?.notification.url;
    },
  }}
>
  {/* content */}
</NavigationContainer>

이 옵션은 웹에서 사용할 수 없습니다

linking.subscribe

getInitialURL와 비슷하게, 기본 딥링크를 처리하는 대신 링크를 처리할 수 있는 커스텀 subscribe 함수를 제공할 수 있습니다.
subscribe함수는 리스너를 argument로 수신하며 처리할 새로운 URL이 있을 때마다 URL 문자열로 호출할 수 있습니다. 설정한 이벤트 수신자의 구독을 취소할 수 있는 정리 기능을 반환해야 합니다.

예를 들어 다음과 같은 작업을 수행하며 딥링크 및 파이버베이스 알림을 모두 처리할 수 있습니다.

<NavigationContainer
  linking={{
    prefixes: ['https://mychat.com', 'mychat://'],
    config: {
      screens: {
        Chat: 'feed/:sort',
      },
    },
    subscribe(listener) {
      const onReceiveURL = ({ url }: { url: string }) => listener(url);

      // 딥링크에서 들어오는 링크감지
      Linking.addEventListener('url', onReceiveURL);

      // 파이어베이스 푸시 알림듣기
      const unsubscribeNotification = messaging().onNotificationOpenedApp(
        (message) => {
          const url = message.notification.url;

          if (url) {
            // URL을 처리해야되는지 여부를 확인하는 사용자 지정 로직
            // 리스너를 호출해서 리액트 네비게이션이 URL을 처리하도록 합니다
            listener(url);
          }
        }
      );

      return () => {
        // 이벤트리스너 clean up
        Linking.removeEventListener('url', onReceiveURL);
        unsubscribeNotification();
      };
    },
  }}
>
  {/* content */}
</NavigationContainer>

이 옵션은 웹에서 사용할 수 없습니다

linking.getStateFromPath

커스텀 구현을 제공함으로써 by providing your own implementation 리액트 네비게이션이 state 객체에 연결하는 방법을 선택적으로 오버라이드(=재정의)할 수 있습니다

<NavigationContainer
  linking={{
    prefixes: ['https://mychat.com', 'mychat://'],
    config: {
      screens: {
        Chat: 'feed/:sort',
      },
    },
    getStateFromPath(path, config) {
      // state객체 반환: '@react-navigation/native'에서 `'getStateFromPath'를 가져와 기본 로직을 재사용할 수 있습니다
    },
  }}
>
  {/* content */}
</NavigationContainer>

linking.getPathFromState

선택적으로 리액트 네비게이션이 자체 구현을 제공해서 링크할 state객체를 나열하는 방법을 재정의할 수 있습니다. getStateFromPath를 지정한 경우 올바른 웹 지원을 위해 필요합니다.

<NavigationContainer
  linking={{
    prefixes: ['https://mychat.com', 'mychat://'],
    config: {
      screens: {
        Chat: 'feed/:sort',
      },
    },
    getPathFromState(state, config) {
      // path가 문자열로 반환됩니다
      // '@react-navigation/native'에서 'getPathFromState'를 가져와 기본 로직을 재사용할 수도 있습니다.
    },
  }}
>
  {/* content */}
</NavigationContainer>

🔖 fallback

딥링크를 해결하는 동안 대체요소로 사용할 리액트요소입니다. 기본값은 null입니다.
네이티브 splash화면이 있는 경우 fallback prop 대신 onReady 를 사용하세요.

🔖 documentTitle

기본적으로 리액트 네비게이션은 웹에서 문서 제목을 포커스된 화면의 title 옵션과 일치하도록 자동으로 업데이트합니다. 이 props을 사용해서 사용하지 않도록 설정하거나 사용자 지정할 수 있습니다.
다음 옵션이 있는 구성 configuration 객체를 수락합니다.

documentTitle.enabled

문서 제목 처리를 사용가능하게 설정할지의 여부.
기본값은 true입니다.

documentTitle.formatter

제목 (텍스트)를 사용자 정의할 때 사용할, 사용자 정의 형식입니다.
기본값은 다음과 같습니다.

(options, route) => options?.title ?? route?.name;
// 사용예시
import { NavigationContainer } from '@react-navigation/native';

function App() {
  return (
    <NavigationContainer
      documentTitle={{
        formatter: (options, route) =>
          `${options?.title ?? route?.name} - My Cool App`,
      }}
    >
      {/* content */}
    </NavigationContainer>
  );
}

🔖 theme

머리글, 탭 표시줄 등과 같은 네비게이션 컴포넌트에 사용할 사용자 지정 테마입니다.
자세한 내용 및 사용 안내서는 theming guide를 참조하세요.

🔖 independent

해당 네비게이션 컨테이너가 상위 컨테이너와 독립적이어야 하는지의 여부를 나타냅니다.
이 값을 true 로 설정하지 않으면 이 컨테이너는 다른 컨테이너 안에 중첩될 수 없습니다.
true로 설정하면 상위 컨테이너에서 하위 컨테이너의 연결이 끊어집니다.

일반적인 리액트 네이티브 앱에서는 이 값을 true로 설정하지 않는 것이 좋습니다.
이 기능은 자체 미니 앱처럼 작동하는 navigation tree가 있고 navigation tree의 외부 화면으로 이동할 필요가 없는 경우에만 유용합니다.

profile
새로운 것을 도전하고 노력한다

0개의 댓글