导航属性参考
您的应用程序中的每个screen
组件都会自动提供navigation
属性。该属性包含各种方便的函数,用于分派导航操作。它看起来像这样
navigation
navigate
- 转到给定的屏幕,这将根据导航器以不同的方式运行goBack
- 返回到上一个屏幕,这将在堆栈中使用时弹出当前屏幕reset
- 用给定的状态替换导航器的导航状态setParams
- 将新的参数合并到路由的参数中dispatch
- 发送一个操作对象来更新导航状态setOptions
- 更新屏幕的选项isFocused
- 检查屏幕是否处于焦点状态canGoBack
- 检查是否可以从当前屏幕返回getState
- 获取导航器的导航状态getParent
- 获取父屏幕的导航对象(如果有)addListener
- 订阅屏幕的事件removeListener
- 取消订阅屏幕的事件
重要的是要强调navigation
属性不会传递给所有组件;只有screen
组件会自动接收此属性!React Navigation 在这里不做任何魔法。例如,如果你要定义一个MyBackButton
组件并将其作为屏幕组件的子组件渲染,你就无法访问它的navigation
属性。但是,如果你希望在任何组件中访问navigation
属性,可以使用 useNavigation
钩子。
setParams
/setOptions
等应该只在useEffect
/useLayoutEffect
/componentDidMount
/componentDidUpdate
等中调用。不要在渲染或构造函数中调用。
与导航器相关的函数
navigation
属性上存在一些基于当前导航器类型的附加函数。
如果导航器是堆栈导航器,则提供了一些navigate
和goBack
的替代方案,你可以使用任何你喜欢的方案。这些函数是
navigation
replace
- 用新的屏幕替换当前屏幕push
- 将新屏幕推入堆栈pop
- 在堆栈中后退popToTop
- 返回堆栈顶部
有关这些方法的更多详细信息,请参阅 堆栈导航器助手 和 原生堆栈导航器助手。
如果导航器是标签导航器,则以下内容也可用
navigation
jumpTo
- 转到标签导航器中的特定屏幕
有关这些方法的更多详细信息,请参阅 底部标签导航器助手、Material 顶部标签导航器助手 和 Material 底部标签导航器助手。
如果导航器是抽屉导航器,则以下内容也可用
navigation
jumpTo
- 转到抽屉导航器中的特定屏幕openDrawer
- 打开抽屉closeDrawer
- 关闭抽屉toggleDrawer
- 切换状态,即从关闭切换到打开,反之亦然
有关这些方法的更多详细信息,请参阅 抽屉导航器助手。
通用 API 参考
您与 navigation
属性的大多数交互都将涉及 navigate
、goBack
和 setParams
。
navigate
navigate
方法允许我们导航到应用程序中的另一个屏幕。它接受以下参数
navigation.navigate(name, params)
name
- 已在某处定义的路由的目标名称params
- 传递给目标路由的参数。
function HomeScreen({ navigation: { navigate } }) {
return (
<View>
<Text>This is the home screen of the app</Text>
<Button
onPress={() =>
navigate('Profile', { names: ['Brent', 'Satya', 'Michaś'] })
}
title="Go to Brent's profile"
/>
</View>
);
}
在 原生堆栈导航器 中,使用屏幕名称调用 navigate
会根据屏幕是否已存在而产生不同的行为。如果屏幕已存在于堆栈的历史记录中,它将返回到该屏幕并删除该屏幕之后的任何屏幕。如果屏幕不存在,它将推送一个新屏幕。
例如,如果您有一个历史记录为 Home > Profile > Settings
的堆栈,并且您调用 navigate(Profile)
,则结果屏幕将为 Home > Profile
,因为它将返回到 Profile
并删除 Settings
屏幕。
默认情况下,屏幕由其名称标识。但您也可以使用 getId
属性来自定义它以考虑参数。
例如,假设您为 Profile
屏幕指定了 getId
属性
<Tab.Screen
name={Profile}
component={ProfileScreen}
getId={({ params }) => params.userId}
/>
现在,如果您有一个历史记录为 Home > Profile (userId: bob) > Settings
的堆栈,并且您调用 navigate(Profile, { userId: 'alice' })
,则结果屏幕将为 Home > Profile (userId: bob) > Settings > Profile (userId: alice)
,因为它将添加一个新的 Profile
屏幕,因为没有找到匹配的屏幕。
goBack
goBack
方法允许我们返回到导航器中的前一个屏幕。
默认情况下,goBack
将从调用它的屏幕返回
function ProfileScreen({ navigation: { goBack } }) {
return (
<View>
<Button onPress={() => goBack()} title="Go back from ProfileScreen" />
</View>
);
}
从特定屏幕返回
考虑以下导航堆栈历史记录
navigation.navigate({ name: SCREEN, key: SCREEN_KEY_A });
navigation.navigate({ name: SCREEN, key: SCREEN_KEY_B });
navigation.navigate({ name: SCREEN, key: SCREEN_KEY_C });
navigation.navigate({ name: SCREEN, key: SCREEN_KEY_D });
现在您位于屏幕 D,并且想要返回到屏幕 A(弹出 D、C 和 B)。然后您可以使用navigate
navigation.navigate({ key: SCREEN_KEY_A }); // will go to screen A FROM screen D
或者,由于屏幕 A 是堆栈的顶部,您可以使用navigation.popToTop()
。
reset
reset
方法允许我们用新状态替换导航器状态
navigation.reset({
index: 0,
routes: [{ name: 'Profile' }],
});
在reset
中指定的 state 对象将用新的 state 对象替换现有的导航状态,即删除现有屏幕并添加新屏幕。如果您想在更改状态时保留现有屏幕,可以使用CommonActions.reset
和dispatch
。
将导航器的 state 对象视为内部对象,并且可能会在次要版本中发生更改。避免使用导航状态 state 对象中的属性,除非您确实需要它们。如果您无法在不依赖 state 对象结构的情况下实现某些功能,请打开一个问题。
setParams
setParams
方法允许我们更新当前屏幕的参数(route.params
)。setParams
的工作方式类似于 React 的setState
- 它将提供的参数对象与当前参数进行浅合并。
function ProfileScreen({ navigation: { setParams } }) {
return (
<Button
onPress={() =>
setParams({
friends:
route.params.friends[0] === 'Brent'
? ['Wojciech', 'Szymon', 'Jakub']
: ['Brent', 'Satya', 'Michaś'],
title:
route.params.title === "Brent's Profile"
? "Lucy's Profile"
: "Brent's Profile",
})
}
title="Swap title and friends"
/>
);
}
setOptions
setOptions
方法允许我们从组件内部设置屏幕选项。如果我们需要使用组件的 props、state 或 context 来配置我们的屏幕,这将很有用。
function ProfileScreen({ navigation, route }) {
const [value, onChangeText] = React.useState(route.params.title);
React.useEffect(() => {
navigation.setOptions({
title: value === '' ? 'No title' : value,
});
}, [navigation, value]);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<TextInput
style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
onChangeText={onChangeText}
value={value}
/>
<Button title="Go back" onPress={() => navigation.goBack()} />
</View>
);
}
此处指定的任何选项都将与定义屏幕时指定的选项进行浅合并。
在使用navigation.setOptions
时,我们建议在屏幕的options
属性中指定一个占位符,并使用navigation.setOptions
更新它。这可以确保更新选项的延迟对用户来说并不明显。它还可以与延迟加载的屏幕一起使用。
您也可以使用React.useLayoutEffect
来减少更新选项的延迟。但我们建议您不要在支持 Web 和服务器端渲染的情况下这样做。
navigation.setOptions
旨在提供在必要时更新现有选项的能力。它不是屏幕上options
属性的替代品。确保只在绝对必要时谨慎使用navigation.setOptions
。
导航事件
屏幕可以使用addListener
方法在navigation
属性上添加监听器。例如,要监听focus
事件
function Profile({ navigation }) {
React.useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
// do something
});
return unsubscribe;
}, [navigation]);
return <ProfileContent />;
}
有关可用事件和 API 用法的更多详细信息,请参阅导航事件。
isFocused
此方法允许我们检查屏幕当前是否处于焦点状态。如果屏幕处于焦点状态,则返回true
,否则返回false
。
const isFocused = navigation.isFocused();
此方法不会在值更改时重新渲染屏幕,主要在回调中使用。您可能希望使用useIsFocused而不是直接使用它,它将返回一个布尔值属性,指示屏幕是否处于焦点状态。
高级 API 参考
dispatch
函数的使用频率要低得多,但如果您无法使用navigate
、goBack
等可用方法来完成所需的操作,它是一个很好的备用方案。我们建议您尽量避免使用dispatch
方法,除非绝对必要。
dispatch
dispatch
方法允许我们发送一个导航操作对象,该对象决定如何更新导航状态。所有导航函数(如navigate
)都在幕后使用dispatch
。
请注意,如果您想调度操作,您应该使用此库提供的操作创建器,而不是直接编写操作对象。
有关可用操作的完整列表,请参阅 导航操作文档。
import { CommonActions } from '@react-navigation/native';
navigation.dispatch(
CommonActions.navigate({
name: 'Profile',
params: {},
})
);
在调度操作对象时,您还可以指定一些其他属性
source
- 应被视为操作来源的路由键。例如,replace
操作将用给定键替换路由。默认情况下,它将使用调度操作的路由键。您可以显式传递undefined
来覆盖此行为。target
- 应将操作应用于的 导航状态 的键。默认情况下,如果导航器未处理操作,则操作会冒泡到其他导航器。如果指定了target
,则如果具有相同键的导航器未处理操作,则操作不会冒泡。
示例
import { CommonActions } from '@react-navigation/native';
navigation.dispatch({
...CommonActions.navigate('Profile'),
source: 'someRoutekey',
target: 'someStatekey',
});
自定义操作创建器
也可以将操作创建器函数传递给 dispatch
。该函数将接收当前状态,并需要返回一个要使用的导航操作对象
import { CommonActions } from '@react-navigation/native';
navigation.dispatch((state) => {
// Add the home route to the start of the stack
const routes = [{ name: 'Home' }, ...state.routes];
return CommonActions.reset({
...state,
routes,
index: routes.length - 1,
});
});
您可以使用此功能来构建您可以在应用程序中使用的自己的助手。以下是一个实现将屏幕插入最后一个屏幕之前的示例
import { CommonActions } from '@react-navigation/native';
const insertBeforeLast = (routeName, params) => (state) => {
const routes = [
...state.routes.slice(0, -1),
{ name: routeName, params },
state.routes[state.routes.length - 1],
];
return CommonActions.reset({
...state,
routes,
index: routes.length - 1,
});
};
然后像这样使用它
navigation.dispatch(insertBeforeLast('Home'));
canGoBack
此方法返回一个布尔值,指示当前导航器或任何父导航器中是否有任何导航历史记录可用。您可以使用它来检查是否可以调用 navigation.goBack()
if (navigation.canGoBack()) {
navigation.goBack();
}
不要使用此方法来渲染内容,因为这不会触发重新渲染。这仅用于回调、事件监听器等。
getParent
此方法返回当前导航器嵌套在其中的父导航器的导航道具。例如,如果您有一个堆栈导航器和一个嵌套在堆栈中的选项卡导航器,那么您可以在选项卡导航器的屏幕中使用 getParent
来获取从堆栈导航器传递的导航道具。
它接受一个可选的 ID 参数来引用特定的父导航器。例如,如果您的屏幕嵌套在多个嵌套级别中,位于带有 id
属性为 "LeftDrawer"
的抽屉导航器下,您可以直接引用它,而无需多次调用 getParent
。
要为导航器使用 ID,首先传递一个唯一的 id
属性
<Drawer.Navigator id="LeftDrawer">{/* .. */}</Drawer.Navigator>
然后在使用 getParent
时,而不是
// Avoid this
const drawerNavigation = navigation.getParent().getParent();
// ...
drawerNavigation?.openDrawer();
您可以这样做
// Do this
const drawerNavigation = navigation.getParent('LeftDrawer');
// ...
drawerNavigation?.openDrawer();
这种方法允许组件不必了解导航器的嵌套结构。因此,强烈建议在使用 getParent
时使用 id
。
如果不存在匹配的父导航器,此方法将返回 undefined
。请确保在使用此方法时始终检查 undefined
。
getState
将导航器的 state 对象视为内部对象,并且可能会在次要版本中发生更改。避免使用导航状态 state 对象中的属性,除非您确实需要它们。如果您无法在不依赖 state 对象结构的情况下实现某些功能,请打开一个问题。
此方法返回包含屏幕的导航器的状态对象。在极少数情况下,获取导航器状态可能很有用。您很可能不需要使用此方法。如果您确实需要,请确保您有充分的理由。
如果您需要状态来渲染内容,您应该使用 useNavigationState
而不是此方法。