不使用 navigation prop 进行导航
有时,您需要从无法访问 navigation
对象的位置触发导航操作,例如 Redux 中间件。对于这种情况,您可以分发导航操作,使用 导航容器上的 ref
。
不要使用 ref
如果
- 您需要在组件内部导航,而无需向下传递
navigation
prop,请参阅useNavigation
代替。ref
的行为有所不同,并且许多特定于屏幕的辅助方法不可用。 - 您需要处理深度链接或通用链接。使用
ref
执行此操作有很多边缘情况。有关处理深度链接的更多信息,请参阅配置链接。 - 您需要与第三方库集成,例如推送通知、branch 等。请参阅深度链接的第三方集成代替。
可以使用 ref
如果
- 您使用状态管理库(如 Redux),您需要从中调度来自中间件的导航操作。
请注意,通常最好从用户操作(例如按钮按下)而不是从 Redux 中间件触发导航。在用户操作时导航使应用程序感觉更灵敏并提供更好的用户体验。因此,在使用 ref
进行导航之前请考虑这一点。 ref
是现有 API 无法处理的情况的应急方案,应仅在极少数情况下使用。
用法
您可以通过 ref
访问根导航对象,并将其传递给 RootNavigation
,我们稍后将使用它进行导航。
- 静态
- 动态
import { createStaticNavigation } from '@react-navigation/native';
import { navigationRef } from './RootNavigation';
/* ... */
const Navigation = createStaticNavigation(RootStack);
export default function App() {
return <Navigation ref={navigationRef} />;
}
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 组件外部使用此方法,事实上,从组件内部使用时效果也很好。
- 静态
- 动态
function navigate(name, params) {
if (navigationRef.isReady()) {
navigationRef.navigate(name, params);
}
}
// Example of usage in any of js modules
//import * as RootNavigation from './path/to/RootNavigation.js';
// ...
// RootNavigation.navigate('ChatScreen', { userName: 'Lucy' });
function Home() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button onPress={() => navigate('Settings', { userName: 'Lucy' })}>
Go to Settings
</Button>
</View>
);
}
function navigate(name, params) {
if (navigationRef.isReady()) {
navigationRef.navigate(name, params);
}
}
// Example of usage in any of js modules
//import * as RootNavigation from './path/to/RootNavigation.js';
// ...
// RootNavigation.navigate('ChatScreen', { userName: 'Lucy' });
function Home() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button onPress={() => navigate('Settings', { userName: 'Lucy' })}>
Go to Settings
</Button>
</View>
);
}
除了 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()
方法,如上面的示例所示。
- 静态
- 动态
const navigationRef = createNavigationContainerRef();
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
}
}
const navigationRef = createNavigationContainerRef();
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
。