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

在没有 navigation prop 的情况下导航

有时您需要从无法访问navigation道具的地方(例如 Redux 中间件)触发导航操作。对于这种情况,您可以使用导航容器上的ref来调度导航操作。

不要使用ref,如果

  • 您需要从组件内部导航,而无需传递navigation道具,请改用useNavigationref的行为不同,并且许多特定于屏幕的辅助方法不可用。
  • 您需要处理深层链接或通用链接。使用ref执行此操作有许多边缘情况。有关处理深层链接的更多信息,请参阅配置链接
  • 您需要与第三方库(例如推送通知、分支等)集成。请改用深层链接的第三方集成

使用ref,如果

  • 您使用状态管理库(例如 Redux),需要从中间件调度导航操作。

请注意,通常最好从用户操作(例如按钮按下)而不是从 Redux 中间件触发导航。在用户操作时导航会使应用程序感觉更具响应性并提供更好的用户体验。因此,在使用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之后调用。

为了避免这种情况,您可以使用isReady()方法,该方法在上述示例中在 ref 上可用。

// 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