导航事件
你可以监听 React Navigation 发出的各种事件以获取某些事件的通知,并在某些情况下覆盖默认操作。有一些核心事件,例如 focus
、blur
等(如下所述)适用于每个导航器,以及仅适用于某些导航器的导航器特定事件。
¥You can listen to various events emitted by React Navigation to get notified of certain events, and in some cases, override the default action. There are few core events such as focus
, blur
etc. (documented below) that work for every navigator, as well as navigator specific events that work only for certain navigators.
除了核心事件之外,每个导航器都可以发出自己的自定义事件。例如,堆栈导航器发出 transitionStart
和 transitionEnd
事件,选项卡导航器发出 tabPress
事件等。你可以在各个导航器的文档中找到有关发出的事件的详细信息。
¥Apart from the core events, each navigator can emit their own custom events. For example, stack navigator emits transitionStart
and transitionEnd
events, tab navigator emits tabPress
event etc. You can find details about the events emitted on the individual navigator's documentation.
核心活动
¥Core events
以下是每个导航器中可用的事件:
¥Following are the events available in every navigator:
focus
当屏幕聚焦时会发出此事件。
¥This event is emitted when the screen comes into focus.
对于大多数情况,useFocusEffect
钩子可能比手动添加监听器更合适。请参阅 本指南 了解更多详细信息,以决定你应该使用哪个 API。
¥For most cases, the useFocusEffect
hook might be appropriate than adding the listener manually. See this guide for more details to decide which API you should use.
blur
当屏幕失去焦点时会发出此事件。
¥This event is emitted when the screen goes out of focus.
state
当导航器的状态更改时会发出此事件。该事件接收事件数据 (event.data.state
) 中的导航器状态。
¥This event is emitted when the navigator's state changes. This event receives the navigator's state in the event data (event.data.state
).
beforeRemove
当用户由于导航操作而离开屏幕时,会发出此事件。可以通过在事件监听器中调用 e.preventDefault()
来阻止用户离开屏幕。
¥This event is emitted when the user is leaving the screen due to a navigation action. It is possible to prevent the user from leaving the screen by calling e.preventDefault()
in the event listener.
React.useEffect(
() =>
navigation.addListener('beforeRemove', (e) => {
if (!hasUnsavedChanges) {
return;
}
// Prevent default behavior of leaving the screen
e.preventDefault();
// Prompt the user before leaving the screen
Alert.alert(
'Discard changes?',
'You have unsaved changes. Are you sure to discard them and leave the screen?',
[
{
text: "Don't leave",
style: 'cancel',
onPress: () => {
// Do nothing
},
},
{
text: 'Discard',
style: 'destructive',
// If the user confirmed, then we dispatch the action we blocked earlier
// This will continue the action that had triggered the removal of the screen
onPress: () => navigation.dispatch(e.data.action),
},
]
);
}),
[navigation, hasUnsavedChanges]
);
阻止此事件中的操作无法与 @react-navigation/native-stack
一起正常工作。我们建议改用 usePreventRemove
钩。
¥Preventing the action in this event doesn't work properly with @react-navigation/native-stack
. We recommend using the usePreventRemove
hook instead.
监听事件
¥Listening to events
有多种方法可以监听来自导航器的事件。每个注册为事件监听器的回调都会接收一个事件对象作为其参数。事件对象包含几个属性:
¥There are multiple ways to listen to events from the navigators. Each callback registered as an event listener receives an event object as its argument. The event object contains few properties:
-
data
- 有关导航器传递的事件的附加数据。如果没有传递数据,则可以是undefined
。¥
data
- Additional data regarding the event passed by the navigator. This can beundefined
if no data was passed. -
target
- 应接收事件的屏幕的路由键。对于某些事件,如果事件与特定屏幕无关,则这可能是undefined
。¥
target
- The route key for the screen that should receive the event. For some events, this maybeundefined
if the event wasn't related to a specific screen. -
preventDefault
- 对于某些事件,事件对象上可能有preventDefault
方法。调用此方法将阻止事件执行的默认操作(例如在tabPress
上切换选项卡)。对阻止操作的支持仅适用于某些事件(例如tabPress
),并不适用于所有事件。¥
preventDefault
- For some events, there may be apreventDefault
method on the event object. Calling this method will prevent the default action performed by the event (such as switching tabs ontabPress
). Support for preventing actions are only available for certain events liketabPress
and won't work for all events.
你可以使用以下 API 监听事件:
¥You can listen to events with the following APIs:
navigation.addListener
在屏幕内,你可以使用 addListener
方法在 navigation
对象上添加监听器。addListener
方法有 2 个参数:事件的类型,以及要在该事件上调用的回调。它返回一个可以调用以取消订阅事件的函数。
¥Inside a screen, you can add listeners on the navigation
object with the addListener
method. The addListener
method takes 2 arguments: type of the event, and a callback to be called on the event. It returns a function that can be called to unsubscribe from the event.
示例:
¥Example:
const unsubscribe = navigation.addListener('tabPress', (e) => {
// Prevent default action
e.preventDefault();
});
通常,你会在 React.useEffect
中为函数组件添加事件监听器。例如:
¥Normally, you'd add an event listener in React.useEffect
for function components. For example:
- Static
- Dynamic
function ProfileScreen() {
const navigation = useNavigation();
React.useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
// Screen was focused
});
return unsubscribe;
}, [navigation]);
React.useEffect(() => {
const unsubscribe = navigation.addListener('blur', () => {
// Screen was unfocused
});
return unsubscribe;
}, [navigation]);
// Rest of the component
}
function ProfileScreen({ navigation }) {
React.useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
// Screen was focused
});
return unsubscribe;
}, [navigation]);
React.useEffect(() => {
const unsubscribe = navigation.addListener('blur', () => {
// Screen was unfocused
});
return unsubscribe;
}, [navigation]);
// Rest of the component
}
unsubscribe
函数可以作为效果中的清理函数返回。
¥The unsubscribe
function can be returned as the cleanup function in the effect.
对于类组件,可以在 componentDidMount
生命周期方法中添加事件,并在 componentWillUnmount
中取消订阅:
¥For class components, you can add the event in the componentDidMount
lifecycle method and unsubscribe in componentWillUnmount
:
class Profile extends React.Component {
componentDidMount() {
this._unsubscribe = navigation.addListener('focus', () => {
// do something
});
}
componentWillUnmount() {
this._unsubscribe();
}
render() {
// Content of the component
}
}
要记住的一件事是,你只能使用 addListener
监听来自直接导航器的事件。例如,如果你尝试在嵌套在选项卡中的堆栈内的屏幕中添加监听器,则它将不会获取 tabPress
事件。如果你需要从父导航器监听事件,则可以使用 navigation.getParent
获取对父屏幕导航对象的引用并添加监听器。
¥One thing to keep in mind is that you can only listen to events from the immediate navigator with addListener
. For example, if you try to add a listener in a screen that's inside a stack that's nested in a tab, it won't get the tabPress
event. If you need to listen to an event from a parent navigator, you may use navigation.getParent
to get a reference to the parent screen's navigation object and add a listener.
const unsubscribe = navigation
.getParent('MyTabs')
.addListener('tabPress', (e) => {
// Do something
});
这里 'MyTabs'
指的是你在要监听其事件的父级 Tab.Navigator
的 id
属性中传递的值。
¥Here 'MyTabs'
refers to the value you pass in the id
prop of the parent Tab.Navigator
whose event you want to listen to.
Screen
上的 listeners
属性
¥listeners
prop on Screen
有时,你可能希望从定义导航器的组件而不是屏幕内部添加监听器。你可以使用 Screen
组件上的 listeners
属性来添加监听器。listeners
属性采用一个对象,其中事件名称作为键,监听器回调作为值。
¥Sometimes you might want to add a listener from the component where you defined the navigator rather than inside the screen. You can use the listeners
prop on the Screen
component to add listeners. The listeners
prop takes an object with the event names as keys and the listener callbacks as values.
示例:
¥Example:
- Static
- Dynamic
const Tab = createBottomTabNavigatior({
screens: {
Chat: {
screen: Chat,
listeners: {
tabPress: (e) => {
// Prevent default action
e.preventDefault;
},
},
},
},
});
<Tab.Screen
name="Chat"
component={Chat}
listeners={{
tabPress: (e) => {
// Prevent default action
e.preventDefault();
},
}}
/>
你还可以传递一个回调,该回调返回带有监听器的对象。它将接收 navigation
和 route
作为参数。
¥You can also pass a callback which returns the object with listeners. It'll receive navigation
and route
as the arguments.
示例:
¥Example:
- Static
- Dynamic
const Tab = createBottomTabNavigatior({
screens: {
Chat: {
screen: Chat,
listeners: ({ navigation, route }) => ({
tabPress: (e) => {
// Prevent default action
e.preventDefault;
// Do something with the `navigation` object
navigation.navigate('AnotherPlace');
},
}),
},
},
});
<Tab.Screen
name="Chat"
component={Chat}
listeners={({ navigation, route }) => ({
tabPress: (e) => {
// Prevent default action
e.preventDefault();
// Do something with the `navigation` object
navigation.navigate('AnotherPlace');
},
})}
/>
导航器上的 screenListeners
属性
¥screenListeners
prop on the navigator
你可以将名为 screenListeners
的 prop 传递给导航器组件,你可以在其中为该导航器的所有屏幕指定事件的监听器。如果你想要监听特定事件而不考虑屏幕,或者想要监听常见事件(例如发送到所有屏幕的 state
),这可能很有用。
¥You can pass a prop named screenListeners
to the navigator component, where you can specify listeners for events from all screens for this navigator. This can be useful if you want to listen to specific events regardless of the screen, or want to listen to common events such as state
which is emitted to all screens.
示例:
¥Example:
- Static
- Dynamic
const Stack = createNativeStackNavigator({
screenListeners: {
state: (e) => {
// Do something with the state
console.log('state changed', e.data);
},
},
screens: {
Home: HomeScreen,
Profile: ProfileScreen,
},
});
<Stack.Navigator
screenListeners={{
state: (e) => {
// Do something with the state
console.log('state changed', e.data);
},
}}
>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
与 listeners
类似,你也可以将函数传递给 screenListeners
。该函数将接收每个屏幕的 navigation
对象 和 route
对象。如果你需要访问 navigation
对象,这会很有用。
¥Similar to listeners
, you can also pass a function to screenListeners
. The function will receive the navigation
object and the route
object for each screen. This can be useful if you need access to the navigation
object.
- Static
- Dynamic
const Tab = createBottomTabNavigatior({
screenListeners: ({ navigation }) => ({
state: (e) => {
// Do something with the state
console.log('state changed', e.data);
// Do something with the `navigation` object
if (!navigation.canGoBack()) {
console.log("we're on the initial screen");
}
},
}),
screens: {
Home: HomeScreen,
Profile: ProfileScreen,
},
});
<Tab.Navigator
screenListeners={({ navigation }) => ({
state: (e) => {
// Do something with the state
console.log('state changed', e.data);
// Do something with the `navigation` object
if (!navigation.canGoBack()) {
console.log("we're on the initial screen");
}
},
})}
>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Profile" component={ProfileScreen} />
</Tab.Navigator>