React Navigationのlinkingを使用しない画面遷移の検討
linking
を使用しない場合は、ディープリンクの受信や、URLに応じた画面遷移などを自身で実装する必要があります。その反面、自由な画面遷移が実現可能です。
以下は、ディープリンク受信時の画面遷移を実現する例です。
ディープリンクの受信と、URLの解析にはExpo Linkingを使用しています。
/**
* ディープリンクURLに応じた画面に遷移させる処理です。
*/
const handleDeepLink = (url: string, navigation: NavigationContainerRef<RootStackParamList>) => {
const parsedURL = Linking.parse(url);
if (parsedURL.path?.startsWith('screen-a')) {
navigation.dispatch(StackActions.push('StackNavigator1', {screen: 'ScreenA'}));
} else if (parsedURL.path?.startsWith('screen-b')) {
navigation.navigate('StackNavigator1', {screen: 'ScreenB'});
} else if (parsedURL.path?.startsWith('screen-d')) {
navigation.dispatch(
CommonActions.reset({
index: 0,
routes: [
{
name: 'TabNavigator2',
state: {
index: 0,
routes: [{name: 'ScreenD'}],
},
},
],
}),
);
}
};
/**
* ディープリンクを受信するコンポーネントです。
*
* このコンポーネントは、NavigationContainerの親コンポーネント(もしくはそれより上位のコンポーネント)として、
* 配置する必要があります。
* NavigationContainerよりも上位に配置することで、NavigationContainerの初期化が完了した後に、
* このコンポーネントのuseEffectが処理されます。
* useEffect内では、NavigationContainerのnavigationRefを使用して、ディープリンクURLに応じた画面遷移を行います。
*/
export const DeepLinkHandler: React.FC<
PropsWithChildren<{navigation: NavigationContainerRef<RootStackParamList>}>
> = ({navigation, children}) => {
// コールド・ウォームスタート
useEffect(() => {
Linking.getInitialURL().then(url => {
if (url) {
handleDeepLink(url, navigation);
}
});
}, [navigation]);
// ホットスタート
useEffect(() => {
const subscription = Linking.addEventListener('url', event => {
handleDeepLink(event.url, navigation);
});
return () => subscription.remove();
}, [navigation]);
return <>{children}</>;
};
ディープリンクの受信やディープリンクと遷移先画面のマッピングなど、linking
に比べて実装する部分は多いのですが、それほどコードが複雑化することはない印象です。
ディープリンクの受信処理を自由に実装できるため、ディープリンクを受信した際の画面遷移に関する仕様を全て満たすこともできます。
注記
未認証時に受け取ったディープリンクの遷移先画面を、認証後に表示する方法は、React Navigationのlinking
使用時に検討した方法と基本的には同じです。
- ディープリンクを受け取った時点で、そのディープリンクをStateに保持
- コールド、ウォームスタートの場合は、Linking.getInitialURL内でStateに設定
- ホットスタートの場合は、Linking.addEventListener内でStateに設定
- 認証後にStateからディープリンクを取得し、ディープリンクに応じた画面へ遷移