React Navigation V5 마이그레이션
react-navigation이 현재 alpha
stage로 올라와있습니다.
Expo 블로그(https://blog.expo.io/announcing-react-navigation-5-0-bd9e5d45569e)에서 확인하고 HackaTalk
에 한 번 적용해보기로 하였습니다.
기존에 react-navigation
은 Brent Vatne 께서 1.0
버전부터 활발하게 개발해주었으며 그간 성능적으로 많은 발전이 있었습니다. 하지만 디자인적으로는 큰 변화는 없었고 주로 feature
가 추가되고는 했습니다. 버전 5부터는 react
디자인패턴에 맞게 사용법이 변경되었으며 이는 react-navigation@next
레포에서 새롭게 개발되고 있습니다.
이제부터는 항목 별로 어떤 부분이 개선 및 수정 되었는지 보겠습니다.
- Static하게 정의된
navgation
props들을 동적으로 변경할 수 있도록 개선되었습니다.
기존의 static binding
식으로 navigationOption
을 설정하는 것이 아닌 HOC
패턴으로 props
를 전달하므로 동적으로 navigation
설정을 변경하는 것이 용이 해졌습니다. 또한, 코드도 더 아름답게 짤 수 있게 되었습니다.
위에서 보이는 것처럼 이제는 navigationOption
을 screenOptions
에 전달하므로 테마 등도 제약 없이 줄 수 있게 되었습니다. 과거에 제가 이슈 #6091에 올린 내용을 보면 특수 상황에서 테마 색상을 동적으로 변경하는 것이 까다로웠습니다. 이 모든 것이 static
하게 내비게이션이 구성되어서 그렇습니다.
새로 나온 navigation
v5는 위와 같은 골칫거리를 말끔하게 해결해 줍니다.
2. 두번째로 타이핑 작성법입니다.
과거에 버전 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
버튼과 통신 하려면 아래와 같이 해주어야 했습니다.
보시면 아시겠지만 navigation state에서 increaseCount
라는 함수를 컴포넌트가 mount되면서 할당하고 있습니다. headerRight
에서는 이를 기다리면서 getParam
을 시도합니다. 문서를 읽으면서 눈살을 찌푸리게 했던 녀석입니다.
버전 5부터는 아래와 같이 헤더와 통신을 할 수 있습니다.
위 예제에서는 함수를 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) 네비게이션에 focus
와 blur
이벤트를 줄 수 있습니다.
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 예제들을 담는 글을 써보도록 하겠습니다 🙏