跳至主要内容
版本:6.x

故障排除

本节试图概述用户在刚开始使用 React Navigation 时经常遇到的问题。这些问题可能与 React Navigation 本身有关,也可能无关。

在排查问题之前,请确保您已升级到**最新可用版本**的软件包。您可以通过再次安装软件包来安装最新版本(例如:npm install package-name)。

更新到最新版本后,我遇到了“无法解析模块”错误

这可能由以下 3 个原因导致

Metro 捆绑器缓存过期

如果模块指向本地文件(即模块名称以 ./ 开头),则可能是由于缓存过期导致。要解决此问题,请尝试以下解决方案。

如果您使用 Expo,请运行

expo start -c

如果您未使用 Expo,请运行

npx react-native start --reset-cache

如果上述方法无效,您还可以尝试以下操作

rm -rf $TMPDIR/metro-bundler-cache-*

缺少对等依赖项

如果模块指向 npm 包(即模块名称不以 ./ 开头),则可能是由于缺少依赖项导致。要解决此问题,请在您的项目中安装依赖项

npm install 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 定制了配置,但未指定 tstsx 作为有效扩展名,则可能会发生这种情况。这些扩展名存在于默认配置中。要检查是否为该问题,请在您的项目中查找 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 install --save-dev metro-react-native-babel-preset

如果您安装了 @babel/core,请将其升级到最新版本。

npm install --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 捆绑器的缓存。

我在使用 TypeScript 时遇到“模块 '[...]' 没有导出成员 'xxx'”错误

如果您项目中使用的是旧版本的 TypeScript,可能会发生这种情况。您可以尝试升级它

npm install --save-dev typescript

我遇到了一个错误“null 不是对象(正在评估 '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" 在 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 ..

现在重建应用程序并在您的设备或模拟器上进行测试。

我遇到了一个错误“尝试注册两个具有相同名称的视图 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 跟踪器中打开一个 issue,解释这个问题。通常对于库来说,包含原生代码的依赖项应该在 peerDependencies 中定义,而不是在 dependencies 中,以避免此类问题。

如果它已经在 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 中,请确保 View 使用 flex: 1 扩展以填充容器

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>
);
}

我收到警告“在导航状态中发现不可序列化值”

如果在参数中传递不可序列化的值,例如类实例、函数等,就会出现这种情况。React Navigation 在这种情况下会发出警告,因为这可能会破坏其他功能,例如 状态持久化深度链接 等。

以下是一些在参数中传递函数的用例示例

  • 将回调传递给要在标题按钮中使用的回调。可以使用 navigation.setOptions 来实现。有关示例,请参阅 标题按钮指南
  • 将回调传递给下一个屏幕,该屏幕可以调用它来传递一些数据。通常可以使用 navigate 来实现。有关示例,请参阅 参数指南
  • 将复杂数据传递给另一个屏幕。而不是将数据传递给 params,可以将复杂数据存储在其他地方(例如全局存储),并传递一个 ID。然后,屏幕可以使用 ID 从全局存储中获取数据。请参阅 参数中应该包含什么
  • 将数据、回调等从父屏幕传递给子屏幕。可以使用 React Context,或者传递一个子回调来传递这些数据,而不是使用参数。请参阅 传递额外属性

如果您不使用状态持久化或深度链接到接受参数中函数的屏幕,那么警告不会影响您,您可以安全地忽略它。要忽略警告,可以使用 LogBox.ignoreLogs

示例

import { LogBox } from 'react-native';

LogBox.ignoreLogs([
'Non-serializable values were found in the navigation state',
]);

我收到“无效的钩子调用。钩子只能在函数组件的主体内部调用”

当您将 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,
}}
/>

同样适用于其他选项,例如 headerLeftheaderRighttabBarIcon 等,以及 tabBardrawerContent 等道具。

屏幕在导航期间卸载/重新挂载

有时您可能已经注意到您的屏幕卸载/重新挂载,或者您的本地组件状态或导航状态在您导航时重置。如果您在渲染期间创建 React 组件,则可能会发生这种情况。

最简单的例子如下

function App() {
return (
<Stack.Navigator>
<Stack.Screen
name="Home"
component={() => {
return <SomeComponent />;
}}
/>
</Stack.Navigator>
);
}

component 道具期待一个 React 组件,但在示例中,它得到的是一个返回 React 元素的函数。虽然表面上组件和返回 React 元素的函数看起来完全一样,但它们在使用时的行为并不相同。

在这里,每次组件重新渲染时,都会创建一个新函数并传递给 component 道具。React 会看到一个新组件,并在渲染新组件之前卸载旧组件。这会导致旧组件中的任何本地状态丢失。React Navigation 会检测并警告此特定情况,但可能还有其他方法您可能会在渲染期间创建组件,而它无法检测到。

另一个易于识别的例子是在另一个组件内部创建组件时

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 调试器(或使用 Chrome 调试器的其他工具,例如 React Native Debugger)时,您可能会遇到与计时相关的各种问题。

这会导致一些问题,例如按钮按下需要很长时间才能注册或根本无法工作,手势和动画缓慢且有故障 等。还可能存在其他功能问题,例如承诺无法解决,超时和间隔无法正常工作 等。

这些问题与 React Navigation 无关,而是由于 Chrome 调试器的工作原理造成的。当连接到 Chrome 调试器时,您的整个应用程序将在 Chrome 上运行,并通过网络上的套接字与原生应用程序进行通信,这会导致延迟和与时间相关的問題。

因此,除非您要调试某些内容,否则最好在未连接到 Chrome 调试器的情况下测试应用程序。如果您使用的是 iOS,则可以改为使用 Safari 调试您的应用程序,它直接在设备上调试应用程序,并且不会出现这些问题,尽管它也有其他缺点。