跳到主要内容
版本: 7.x

导航事件

你可以监听 React Navigation 发出的各种事件,以获取特定事件的通知,并且在某些情况下,可以覆盖默认操作。有一些核心事件,例如 focusblur 等(如下所述),它们适用于每个导航器,以及仅适用于某些导航器的特定于导航器的事件。

除了核心事件之外,每个导航器都可以发出他们自己的自定义事件。例如,堆栈导航器发出 transitionStarttransitionEnd 事件,标签导航器发出 tabPress 事件等。你可以在各个导航器的文档中找到有关发出事件的详细信息。

核心事件

以下是每个导航器中可用的事件

focus

当屏幕进入焦点时,会发出此事件。

对于大多数情况,useFocusEffect hook 可能比手动添加监听器更合适。请参阅本指南以获取更多详细信息,以决定应使用哪个 API。

blur

当屏幕失去焦点时,会发出此事件。

state

当导航器的状态更改时,会发出此事件。此事件在事件数据 (event.data.state) 中接收导航器的状态。

beforeRemove

当用户由于导航操作而离开屏幕时,会发出此事件。可以通过在事件监听器中调用 e.preventDefault() 来阻止用户离开屏幕。

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 hook

监听事件

有多种方法可以监听来自导航器的事件。注册为事件监听器的每个回调都会接收一个事件对象作为其参数。事件对象包含一些属性

  • data - 导航器传递的有关事件的其他数据。如果没有传递数据,则可能为 undefined
  • target - 应该接收事件的屏幕的路由键。对于某些事件,如果事件与特定屏幕无关,则可能为 undefined
  • preventDefault - 对于某些事件,事件对象上可能有一个 preventDefault 方法。调用此方法将阻止事件执行的默认操作(例如切换 tabPress 上的标签)。仅某些事件(例如 tabPress)支持阻止操作,并且不适用于所有事件。

你可以使用以下 API 监听事件

在屏幕内部,你可以使用 addListener 方法在 navigation 对象上添加监听器。addListener 方法接受 2 个参数:事件的类型和事件发生时要调用的回调。它返回一个可以调用的函数来取消订阅事件。

示例

const unsubscribe = navigation.addListener('tabPress', (e) => {
// Prevent default action
e.preventDefault();
});

通常,你会在函数组件的 React.useEffect 中添加事件监听器。例如

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
}
Snack 上尝试

unsubscribe 函数可以作为 effect 中的清理函数返回。

对于类组件,你可以在 componentDidMount 生命周期方法中添加事件,并在 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 获取对父屏幕的 navigation 对象的引用并添加监听器。

const unsubscribe = navigation
.getParent('MyTabs')
.addListener('tabPress', (e) => {
// Do something
});

这里 'MyTabs' 指的是你在你想要监听其事件的父 Tab.Navigatorid prop 中传递的值。

Screen 上的 listeners prop

有时你可能想从定义导航器的组件而不是屏幕内部添加监听器。你可以使用 Screen 组件上的 listeners prop 添加监听器。listeners prop 接受一个对象,其中事件名称作为键,监听器回调作为值。

示例

const Tab = createBottomTabNavigatior({
screens: {
Chat: {
screen: Chat,
listeners: {
tabPress: (e) => {
// Prevent default action
e.preventDefault;
},
},
},
},
});

你还可以传递一个回调函数,该函数返回带有监听器的对象。它将接收 navigationroute 作为参数。

示例

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

导航器上的 screenListeners prop

你可以将名为 screenListeners 的 prop 传递给导航器组件,你可以在其中为来自此导航器的所有屏幕的事件指定监听器。如果你想监听特定事件而不管屏幕如何,或者想监听所有屏幕发出的常见事件(例如 state),这将非常有用。

示例

const Stack = createNativeStackNavigator({
screenListeners: {
state: (e) => {
// Do something with the state
console.log('state changed', e.data);
},
},
screens: {
Home: HomeScreen,
Profile: ProfileScreen,
},
});

listeners 类似,你还可以将函数传递给 screenListeners。该函数将接收每个屏幕的 navigation 对象route 对象。如果你需要访问 navigation 对象,这将非常有用。

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