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

阻止返回

有时你可能想要阻止用户离开某个屏幕,例如,如果存在未保存的更改,你可能想要显示一个确认对话框。你可以使用 beforeRemove 事件来实现这一点。

事件监听器接收触发它的 action。你可以在确认后再次调度此操作,或检查操作对象以确定要执行的操作。

示例

function EditText({ navigation }) {
const [text, setText] = React.useState('');
const hasUnsavedChanges = Boolean(text);

React.useEffect(
() =>
navigation.addListener('beforeRemove', (e) => {
if (!hasUnsavedChanges) {
// If we don't have unsaved changes, then we don't need to do anything
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: () => {} },
{
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]
);

return (
<TextInput
value={text}
placeholder="Type something…"
onChangeText={setText}
/>
);
}

以前,实现此功能的方法是

  • 覆盖标题中的返回按钮
  • 禁用向后滑动手势
  • 覆盖 Android 上的系统返回按钮/手势

但是,除了代码更少之外,这种方法还有许多重要的区别

  • 它不与任何特定按钮耦合,从自定义按钮返回也会触发它
  • 它不与任何特定操作耦合,任何从状态中移除路由的操作都会触发它
  • 它适用于嵌套导航器,例如,如果屏幕由于父导航器中的操作而被移除
  • 用户仍然可以在堆栈导航器中向后滑动,但是,如果事件被阻止,滑动将被取消
  • 可以继续执行触发事件的相同操作

限制

使用 beforeRemove 事件时,需要注意一些限制。该事件**仅**在由于导航状态更改而移除屏幕时触发。例如

  • 用户在堆栈中的屏幕上按下了返回按钮。
  • 用户执行了向后滑动手势。
  • 一些操作,例如 popreset 被调度,这会从状态中移除屏幕。

当屏幕被取消焦点但未被移除时,此事件**不会**被触发。例如

  • 用户在堆栈中将新屏幕推送到带有侦听器的屏幕之上。
  • 用户从一个标签/抽屉屏幕导航到另一个标签/抽屉屏幕。

当用户由于导航状态无法控制的操作而退出屏幕时,该事件也不会被触发

  • 用户关闭应用程序(例如,通过按下主屏幕上的返回按钮,关闭浏览器中的标签页,从应用程序切换器中关闭应用程序等)。您还可以使用 hardwareBackPress 事件在 Android 上,beforeunload 事件在 Web 上等来处理其中的一些情况。
  • 屏幕由于条件渲染或父组件被卸载而被卸载。
  • 屏幕由于使用 @react-navigation/bottom-tabs@react-navigation/drawer 等的 unmountOnBlur 选项而被卸载。

除了上述情况之外,此功能也不适用于 @react-navigation/native-stack。要使其正常工作,您需要

  • 禁用屏幕的滑动手势 (gestureEnabled: false)。
  • 使用自定义返回按钮覆盖标题中的原生返回按钮 (headerLeft: (props) => <CustomBackButton {...props} />)。