React Navigation V5 마이그레이션

Hyo
Cross-Platform Korea
9 min readNov 8, 2019

react-navigation이 현재 alpha stage로 올라와있습니다.

Expo 블로그(https://blog.expo.io/announcing-react-navigation-5-0-bd9e5d45569e)에서 확인하고 HackaTalk에 한 번 적용해보기로 하였습니다.

기존에 react-navigationBrent Vatne 께서 1.0 버전부터 활발하게 개발해주었으며 그간 성능적으로 많은 발전이 있었습니다. 하지만 디자인적으로는 큰 변화는 없었고 주로 feature가 추가되고는 했습니다. 버전 5부터는 react 디자인패턴에 맞게 사용법이 변경되었으며 이는 react-navigation@next 레포에서 새롭게 개발되고 있습니다.

이제부터는 항목 별로 어떤 부분이 개선 및 수정 되었는지 보겠습니다.

  1. Static하게 정의된 navgation props들을 동적으로 변경할 수 있도록 개선되었습니다.

기존의 static binding 식으로 navigationOption을 설정하는 것이 아닌 HOC 패턴으로 props를 전달하므로 동적으로 navigation 설정을 변경하는 것이 용이 해졌습니다. 또한, 코드도 더 아름답게 짤 수 있게 되었습니다.

관련 `PR`은 https://github.com/dooboolab/hackatalk-mobile/pull/45 여기서 확인하세요.

위에서 보이는 것처럼 이제는 navigationOptionscreenOptions에 전달하므로 테마 등도 제약 없이 줄 수 있게 되었습니다. 과거에 제가 이슈 #6091에 올린 내용을 보면 특수 상황에서 테마 색상을 동적으로 변경하는 것이 까다로웠습니다. 이 모든 것이 static 하게 내비게이션이 구성되어서 그렇습니다.

새로 나온 navigation v5는 위와 같은 골칫거리를 말끔하게 해결해 줍니다.

2. 두번째로 타이핑 작성법입니다.

변경된 `navigation` 타입
react-navigation v5 타입을 주는 상황입니다.
위와 같이 해줌으로 아래와 같이 `param`을 전달하는 타이핑을 전달하고 있습니다. 과거에는 `NavigationStateParam`을 extend 받고 추가적인 `state`를 정의해주고는 했습니다.

과거에 버전 4 이하 react-navigation에서는 아래와 같이 타이핑을 지정해주었습니다.

// 별도 타입 정의 파일에서 아래와 같이 공통으로 쓰는 NavigationProps 정의
export type DefaultNavigationProps< T extends NavigationState =
NavigationState> = NavigationScreenProp<T, NavigationParams>;
// Screen component에서 타입 정의
interface CustomNavigationState extends NavigationState {
params: { chatId: string; };
}
interface Props {
navigation: DefaultNavigationProps<CustomNavigationState>;
}

V5부터는 아래와 같이 해주고 있습니다.

// 별도 타입 정의 파일에서 아래와 같이 공통으로 쓰는 NavigationProps 정의
type StackParamList = {
Default: undefined;
Chat: { chatId: string };
}
export type DefaultNavigationProps< T extends keyof StackParamList = 'Default'> = StackNavigationProp<StackParamList, T>;// Screen component에서 타입 정의
export interface Props {
navigation: DefaultNavigationProps<'Chat'>;
route: any;
}

3. Header button과의 상호작용이 합리적입니다.

우선 과거 버전에서는 Header 버튼과 통신 하려면 아래와 같이 해주어야 했습니다.

https://reactnavigation.org/docs/en/header-buttons.html

보시면 아시겠지만 navigation state에서 increaseCount라는 함수를 컴포넌트가 mount되면서 할당하고 있습니다. headerRight에서는 이를 기다리면서 getParam을 시도합니다. 문서를 읽으면서 눈살을 찌푸리게 했던 녀석입니다.

버전 5부터는 아래와 같이 헤더와 통신을 할 수 있습니다.

https://reactnavigation.org/docs/en/next/header-buttons.html

위 예제에서는 함수를 headerRight 버튼에서 바로 할당해주고 있습니다. 여기서 params를 수정하여 HomeScreen 안에서 route props를 이용하여 바로 불러다 쓸 수 있습니다. 여기서route는 앞으로 getParam을 대체 하기도 합니다.

4. 추가적으로 react-navigation에서 가능해진 기능들이 있습니다.

(4–1)Back 버튼이 눌렸을 때 useBackButton을 hook을 통해서 백 버튼 action을 컨트롤 할 수 있습니다.

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

// ...

const ref = React.useRef();

useBackButton(ref);

return <NavigationContainer ref={ref}>{/* content */}</NavigationContainer>;

(4–2) 동일하게 scrollTo 를 이용하여 어디서나 스크롤뷰를 컨트롤할 수 있습니다.

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

// ...

const ref = React.useRef();

useScrollToTop(ref);

return <ScrollView ref={ref}>{/* content */}</ScrollView>;
  • 위와 같이 해줌으로 탭을 이동할 때 스크롤을 제일 위로 줄 수 있습니다.

(4–3) useLinking 을 통해 deep-linking 도 가능하지만 화면이 열려있을 때는 state만 변경해줄 수 있습니다.

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

// ...

const ref = React.useRef();

const { getInitialState } = useLinking(ref, {
prefixes: ['https://myapp.com', 'myapp://'],
});

const [isReady, setIsReady] = React.useState(false);
const [initialState, setInitialState] = React.useState();

React.useEffect(() => {
getInitialState()
.catch(() => {})
.then(state => {
if (state !== undefined) {
setInitialState(state);
}

setIsReady(true);
});
}, [getInitialState]);

if (!isReady) {
return null;
}

return (
<NavigationContainer initialState={initialState} ref={ref}>
{/* content */}
</NavigationContainer>
);

(4–4) 네비게이션에 focusblur 이벤트를 줄 수 있습니다.

function Profile({ navigation }) {
React.useEffect(() =>
navigation.addListener('focus', () => {
// do something
})
);

return <ProfileContent />;
}
navigation.emit({
type: 'transitionStart',
data: { blurring: false },
target: route.key,
});

이상으로 포스팅을 마치겠습니다. 다음에는 react-navigation v5 예제들을 담는 글을 써보도록 하겠습니다 🙏

--

--