トラブルシューティング
このセクションでは、React Navigation の使用に慣れる際にユーザーが頻繁に遭遇する問題を概説しようと試みます。これらの問題は、React Navigation 自体に関連している場合も、そうでない場合もあります。
問題のトラブルシューティングを行う前に、必ずパッケージの利用可能な最新バージョンにアップグレードしてください。パッケージを再度インストールすることで、最新バージョンをインストールできます (例: npm install package-name
)。
最新バージョンにアップデート後、「Unable to resolve module」というエラーが発生する
これには3つの理由が考えられます。
Metro bundler の古いキャッシュ
モジュールがローカルファイル (つまり、モジュールの名前が ./
で始まる) を指している場合、それはおそらく古いキャッシュが原因です。これを修正するには、次の解決策を試してください。
Expo を使用している場合は、次を実行します。
expo start -c
Expo を使用していない場合は、次を実行します。
npx react-native start --reset-cache
それでもうまくいかない場合は、次のことも試すことができます。
rm -rf $TMPDIR/metro-bundler-cache-*
ピア依存関係の欠落
モジュールが npm パッケージ (つまり、モジュールの名前が ./
で始まらない) を指している場合、それはおそらく依存関係の欠落が原因です。これを修正するには、プロジェクトに依存関係をインストールします。
- npm
- Yarn
- pnpm
npm install name-of-the-module
yarn add name-of-the-module
pnpm add name-of-the-module
場合によっては、インストールが破損していることが原因であることもあります。キャッシュのクリアがうまくいかなかった場合は、node_modules
フォルダーを削除して、再度 npm install
を実行してみてください。
metro 構成での拡張子の欠落
エラーが次のようになることがあります。
Error: While trying to resolve module "@react-navigation/native" from file "/path/to/src/App.js", the package "/path/to/node_modules/@react-navigation/native/package.json" was successfully found. However, this package itself specifies a "main" module field that could not be resolved ("/path/to/node_modules/@react-navigation/native/src/index.tsx"
これは、metro のカスタム構成があり、ts
および tsx
を有効な拡張子として指定していない場合に発生する可能性があります。これらの拡張子は、デフォルトの構成に存在します。これが問題であるかどうかを確認するには、プロジェクト内の metro.config.js
ファイルを探し、sourceExts
オプションを指定しているかどうかを確認します。少なくとも次の構成が必要です。
sourceExts: ['js', 'json', 'ts', 'tsx'];
これらの拡張子がない場合は、それらを追加して、上記のセクションに示すように metro キャッシュをクリアします。
「SyntaxError in @react-navigation/xxx/xxx.tsx」または「SyntaxError: /xxx/@react-navigation/xxx/xxx.tsx: Unexpected token」というエラーが発生する
これは、metro-react-native-babel-preset
パッケージの古いバージョンを使用している場合に発生する可能性があります。最新バージョンにアップグレードしてみてください。
- npm
- Yarn
- pnpm
npm install --save-dev metro-react-native-babel-preset
yarn add --dev metro-react-native-babel-preset
pnpm add --save-dev metro-react-native-babel-preset
@babel/core
がインストールされている場合は、それも最新バージョンにアップグレードしてください。
- npm
- Yarn
- pnpm
npm install --save-dev @babel/core
yarn add --dev @babel/core
pnpm add --save-dev @babel/core
パッケージのアップグレードがうまくいかない場合は、node_modules
とロックファイルを削除して、依存関係を再インストールすることもできます。
npm
を使用している場合
rm -rf node_modules
rm package-lock.json
npm install
yarn
を使用している場合
rm -rf node_modules
rm yarn.lock
yarn
パッケージのアップグレードまたは再インストールの後、ページの先頭の手順に従って Metro bundler のキャッシュもクリアする必要があります。
TypeScript を使用しているときに、「Module '[...]' has no exported member 'xxx'」というエラーが発生する
これは、プロジェクトに古いバージョンの TypeScript がある場合に発生する可能性があります。アップグレードを試すことができます。
- npm
- Yarn
- pnpm
npm install --save-dev typescript
yarn add --dev typescript
pnpm add --save-dev typescript
「null is not an object (evaluating 'RNGestureHandlerModule.default.Direction')」というエラーが発生する
このエラーといくつかの類似のエラーは、ベア React Native プロジェクトがあり、ライブラリ react-native-gesture-handler
ライブラリがリンクされていない場合に発生する可能性があります。
React Native 0.60 以降ではリンクは自動で行われるため、ライブラリを手動でリンクした場合は、最初にリンクを解除します。
react-native unlink react-native-gesture-handler
iOS でテストしていて、Mac を使用している場合は、ios/
フォルダーで pod install
を実行したことを確認してください。
cd ios
pod install
cd ..
アプリを再ビルドして、デバイスまたはシミュレーターでテストします。
「requireNativeComponent: "RNCSafeAreaProvider" was not found in the UIManager」というエラーが発生する
このエラーといくつかの類似のエラーは、ベア React Native プロジェクトがあり、ライブラリ react-native-safe-area-context
ライブラリがリンクされていない場合に発生する可能性があります。
React Native 0.60 以降ではリンクは自動で行われるため、ライブラリを手動でリンクした場合は、最初にリンクを解除します。
react-native unlink react-native-safe-area-context
iOS でテストしていて、Mac を使用している場合は、ios/
フォルダーで pod install
を実行したことを確認してください。
cd ios
pod install
cd ..
アプリを再ビルドして、デバイスまたはシミュレーターでテストします。
「Tried to register two views with the same name RNCSafeAreaProvider」というエラーが発生する
これは、複数のバージョンの react-native-safe-area-context
がインストールされている場合に発生する可能性があります。
Expo マネージドワークフローを使用している場合は、互換性のないバージョンをインストールした可能性があります。正しいバージョンをインストールするには、次を実行します。
npx expo install react-native-safe-area-context
エラーが修正されなかった場合、または Expo マネージドワークフローを使用していない場合は、どのパッケージが react-native-safe-area-context
の異なるバージョンに依存しているかを確認する必要があります。
yarn
を使用している場合は、次を実行します。
yarn why react-native-safe-area-context
npm
を使用している場合は、次を実行します。
npm ls react-native-safe-area-context
これにより、使用しているパッケージが react-native-safe-area-context
に依存しているかどうかがわかります。それがサードパーティのパッケージである場合は、問題に関する説明を、関連するリポジトリの Issue Tracker で公開する必要があります。一般に、ライブラリの場合、ネイティブコードを含む依存関係は、このような問題を回避するために dependencies
ではなく peerDependencies
で定義する必要があります。
既に peerDependencies
にあり、dependencies
にない場合、および npm
を使用している場合は、パッケージに定義されている互換性のないバージョン範囲が原因である可能性があります。ライブラリの作成者は、そのような場合に、より広範囲のバージョンをインストールできるように、バージョン範囲を緩和する必要があります。
yarn
を使用している場合は、resolutions
を使用してインストールされているバージョンを一時的にオーバーライドすることもできます。package.json
に次を追加します。
"resolutions": {
"react-native-safe-area-context": "<version you want to use>"
}
次に、次を実行します。
yarn
iOS を使用しており、Expo マネージドワークフローを使用していない場合は、次も実行します。
cd ios
pod install
cd ..
アプリを再ビルドして、デバイスまたはシミュレーターでテストします。
View
を追加した後、画面に何も表示されない
コンテナを View
でラップする場合は、flex: 1
を使用して、View
がコンテナを埋め尽くすようにストレッチされていることを確認します。
import * as React from 'react';
import { View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
export default function App() {
return (
<View style={{ flex: 1 }}>
<NavigationContainer>{/* ... */}</NavigationContainer>
</View>
);
}
「Non-serializable values were found in the navigation state」という警告が表示される
これは、クラスインスタンス、関数などのシリアル化できない値を params で渡している場合に発生する可能性があります。この場合、React Navigation は、状態の永続化、ディープリンクなどの他の機能が壊れる可能性があるため、警告を表示します。
params で関数を渡すユースケースの例を次に示します。
- ヘッダーボタンで使用するコールバックを渡すため。これは、代わりに
navigation.setOptions
を使用して実現できます。例については、ヘッダーボタンのガイドを参照してください。 - コールバックを次の画面に渡して、データを戻すために呼び出すことができます。通常は、代わりに
navigate
を使用することで実現できます。例については、paramsのガイドを参照してください。 - 複雑なデータを別の画面に渡す場合。データを
params
として渡す代わりに、その複雑なデータを別の場所(グローバルストアなど)に保存し、代わりにIDを渡すことができます。その後、画面はIDを使用してグローバルストアからデータを取得できます。「paramsに入れるべきもの」を参照してください。 - 親画面から子画面にデータやコールバックなどを渡す場合。React Contextを使用するか、paramsを使用する代わりに子コールバックを渡して、これらを下に渡すことができます。「追加のpropsの渡し方」を参照してください。
状態の永続化や、paramsに関数を受け入れる画面へのディープリンクを使用しない場合は、この警告は影響せず、無視しても問題ありません。警告を無視するには、LogBox.ignoreLogs
を使用できます。
例
import { LogBox } from 'react-native';
LogBox.ignoreLogs([
'Non-serializable values were found in the navigation state',
]);
「Invalid hook call. Hooks can only be called inside of the body of a function component」というエラーが表示される
これは、React要素を返す関数を受け入れるオプションにReactコンポーネントを渡すと発生する可能性があります。たとえば、ネイティブスタックナビゲーターのheaderTitle
オプションは、React要素を返す関数を期待しています。
<Stack.Screen
name="Home"
component={Home}
option={{ headerTitle: (props) => <MyTitle {...props} /> }}
/>
ここに直接関数を渡すと、フックを使用するときにこのエラーが発生します。
<Stack.Screen
name="Home"
component={Home}
option={{
// This is not correct
headerTitle: MyTitle,
}}
/>
headerLeft
、headerRight
、tabBarIcon
などの他のオプションや、tabBar
、drawerContent
などのpropsにも同じことが当てはまります。
ナビゲーション中に画面がアンマウント/再マウントされる
ナビゲート時に画面がアンマウント/再マウントされたり、ローカルコンポーネントの状態やナビゲーションの状態がリセットされたりすることに気づくかもしれません。これは、レンダリング中にReactコンポーネントを作成している場合に発生する可能性があります。
最も簡単な例は、次のようなものです。
function App() {
return (
<Stack.Navigator>
<Stack.Screen
name="Home"
component={() => {
return <SomeComponent />;
}}
/>
</Stack.Navigator>
);
}
component
プロパティはReactコンポーネントを期待していますが、この例では、React要素を返す関数を取得しています。表面上、コンポーネントとReact要素を返す関数はまったく同じに見えますが、使用するときの動作は異なります。
ここでは、コンポーネントが再レンダリングされるたびに、新しい関数が作成され、component
プロパティに渡されます。Reactは新しいコンポーネントとみなし、新しいコンポーネントをレンダリングする前に、以前のコンポーネントをアンマウントします。これにより、古いコンポーネントのローカル状態が失われます。React Navigationは、この特定のケースを検出し、警告しますが、検出できない方法でレンダリング中にコンポーネントを作成している可能性もあります。
これを簡単に特定できるもう1つの例は、別のコンポーネント内でコンポーネントを作成する場合です。
function App() {
const Home = () => {
return <SomeComponent />;
};
return (
<Stack.Navigator>
<Stack.Screen name="Home" component={Home} />
</Stack.Navigator>
);
}
または、別のコンポーネント内で高階コンポーネント(Reduxのconnect
や、コンポーネントを受け入れるwithX
関数など)を使用する場合です。
function App() {
return (
<Stack.Navigator>
<Stack.Screen name="Home" component={withSomeData(Home)} />
</Stack.Navigator>
);
}
不明な場合は、画面として使用しているコンポーネントがReactコンポーネントの外で定義されていることを常に確認するのが最善です。別のファイルで定義してインポートするか、同じファイルの一番上のレベルのスコープで定義できます。
const Home = () => {
return <SomeComponent />;
};
function App() {
return (
<Stack.Navigator>
<Stack.Screen name="Home" component={Home} />
</Stack.Navigator>
);
}
これはReact Navigationに特有のものではなく、React全般に関連するものです。React Navigationを使用しているかどうかに関わらず、レンダリング中にコンポーネントを作成することは常に避ける必要があります。
Chromeデバッガーに接続するとアプリが正常に動作しない
アプリがChromeデバッガー(またはReact Native Debuggerなど、Chromeデバッガーを使用する他のツール)に接続されている場合、タイミングに関連するさまざまな問題が発生する可能性があります。
これにより、ボタンの押下を登録するのに時間がかかったり、まったく動作しなかったり、ジェスチャーやアニメーションが遅くバギーになったりするなどの問題が発生する可能性があります。また、Promiseが解決しなかったり、タイムアウトやインターバルが正しく機能しなかったりするなど、他の機能上の問題も発生する可能性があります。
これらの問題はReact Navigationとは関係なく、Chromeデバッガーの仕組みの性質によるものです。Chromeデバッガーに接続すると、アプリ全体がChrome上で実行され、ネットワーク経由でソケットを介してネイティブアプリと通信します。これにより、遅延やタイミングに関連する問題が発生する可能性があります。
そのため、何かをデバッグしようとしている場合を除き、Chromeデバッガーに接続せずにアプリをテストする方が適切です。iOSを使用している場合は、代わりにSafariを使用してアプリをデバッグできます。これにより、デバイス上でアプリが直接デバッグされ、これらの問題はありませんが、他の欠点もあります。