ナビゲーションプロップなしでのナビゲーション
navigation
プロップにアクセスできない場所(Reduxミドルウェアなど)からナビゲーションアクションをトリガーする必要がある場合があります。そのような場合、ナビゲーションコンテナのref
を使用してナビゲーションアクションをディスパッチできます。
ref
を使用しないでください。
navigation
プロップを下に渡す必要なく、コンポーネント内からナビゲーションを行う必要がある場合、代わりにuseNavigation
を使用してください。ref
は異なる動作をし、画面固有の多くのヘルパーメソッドは使用できません。- ディープリンクまたはユニバーサルリンクを処理する必要がある場合。
ref
を使用してこれを行うと、多くのエッジケースが発生します。ディープリンキングの処理の詳細については、リンクの設定を参照してください。 - プッシュ通知、Branchなど、サードパーティライブラリと統合する必要がある場合。代わりにディープリンキングのサードパーティ統合を参照してください。
ref
を使用してください。
- Reduxなどの状態管理ライブラリを使用しており、ミドルウェアからナビゲーションアクションをディスパッチする必要がある場合。
通常、Reduxミドルウェアではなく、ボタン押下などのユーザーアクションからナビゲーションをトリガーする方が良いことに注意してください。ユーザーアクションでのナビゲーションは、アプリの反応性を高め、より優れたUXを提供します。そのため、ナビゲーションにref
を使用する前に、この点を考慮してください。ref
は、既存のAPIでは処理できないシナリオのための脱出ハッチであり、まれな状況でのみ使用する必要があります。
使用方法
ref
を使用してルートナビゲーションオブジェクトにアクセスし、それを後でナビゲーションに使用されるRootNavigation
に渡すことができます。
// App.js
import { NavigationContainer } from '@react-navigation/native';
import { navigationRef } from './RootNavigation';
export default function App() {
return (
<NavigationContainer ref={navigationRef}>{/* ... */}</NavigationContainer>
);
}
次のステップでは、ユーザー定義のナビゲーションアクションをディスパッチする単純なモジュールであるRootNavigation
を定義します。
// RootNavigation.js
import { createNavigationContainerRef } from '@react-navigation/native';
export const navigationRef = createNavigationContainerRef();
export function navigate(name, params) {
if (navigationRef.isReady()) {
navigationRef.navigate(name, params);
}
}
// add other navigation functions that you need and export them
次に、任意のJavaScriptモジュールでRootNavigation
をインポートし、そこからエクスポートした関数呼び出しを行います。このアプローチはReactコンポーネントの外で使用できますが、実際にはコンポーネント内から使用した場合にも機能します。
// any js module
import * as RootNavigation from './path/to/RootNavigation.js';
// ...
RootNavigation.navigate('ChatScreen', { userName: 'Lucy' });
navigate
以外にも、他のナビゲーションアクションを追加できます。
import { StackActions } from '@react-navigation/native';
// ...
export function push(...args) {
if (navigationRef.isReady()) {
navigationRef.dispatch(StackActions.push(...args));
}
}
このアクションを処理するには、スタックナビゲーターをレンダリングする必要があることに注意してください。詳細については、ネストに関するドキュメントを確認することをお勧めします。
テストを作成する際には、ナビゲーション関数をモックし、正しい関数が正しいパラメーターで呼び出されたかどうかをアサーションできます。
初期化の処理
このパターンを使用する際には、アプリでのナビゲーションの失敗を避けるために、いくつかの点に注意する必要があります。
ref
はナビゲーションコンテナがレンダリングされた後にのみ設定されます。これは、ディープリンクを処理する場合、非同期になる可能性があります。- アクションを処理するには、ナビゲーターをレンダリングする必要があります。ナビゲーターがないと
ref
は準備できません。
ナビゲーターをレンダリングせずに、またはナビゲーターのマウントが完了する前にナビゲーションを試行すると、エラーが印刷され、何も行われません。そのため、アプリのマウントが完了するまでに行うことを決定するための追加のチェックを追加する必要があります。
例として、アプリのどこかに画面があり、その画面がuseEffect
/componentDidMount
でReduxアクションをディスパッチするシナリオを考えてみましょう。ミドルウェアでこのアクションをリスニングし、取得時にナビゲーションを実行しようとします。これはエラーをスローします。なぜなら、この時点では親ナビゲーターのマウントが完了しておらず、準備できていないからです。親のuseEffect
/componentDidMount
は常に子のuseEffect
/componentDidMount
の**後**に呼び出されます。
これを回避するには、上記の例に示すように、refで使用可能なisReady()
メソッドを使用できます。
// RootNavigation.js
import * as React from 'react';
export const navigationRef = createNavigationContainerRef();
export function navigate(name, params) {
if (navigationRef.isReady()) {
// Perform navigation if the react navigation is ready to handle actions
navigationRef.navigate(name, params);
} else {
// You can decide what to do if react navigation is not ready
// You can ignore this, or add these actions to a queue you can call later
}
}
ナビゲーターがレンダリングされているかどうかが不明な場合は、navigationRef.current.getRootState()
を呼び出すことができます。ナビゲーターがレンダリングされている場合は有効な状態オブジェクトが返され、そうでない場合はundefined
が返されます。