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

usePreventRemove

usePreventRemove Hook 允许你阻止用户离开屏幕。例如,如果有未保存的更改,你可能希望在用户可以导航离开之前显示确认对话框。

该 Hook 接受 2 个参数

  • preventRemove:一个布尔值,指示是否阻止屏幕被移除。
  • callback:一个函数,当移除被阻止时将被调用。这可以用于显示确认对话框。

回调函数接收一个 data 对象,其中包含触发屏幕移除的 action。你可以在确认后再次 dispatch 这个 action,或者检查 action 对象来确定要执行的操作。

示例

const EditTextScreen = () => {
const [text, setText] = React.useState('');
const navigation = useNavigation();

const hasUnsavedChanges = Boolean(text);

usePreventRemove(hasUnsavedChanges, ({ data }) => {
if (Platform.OS === 'web') {
const discard = confirm(
'You have unsaved changes. Discard them and leave the screen?'
);

if (discard) {
navigation.dispatch(data.action);
}
} else {
Alert.alert(
'Discard changes?',
'You have unsaved changes. Discard them and leave the screen?',
[
{ text: "Don't leave", style: 'cancel', onPress: () => {} },
{
text: 'Discard',
style: 'destructive',
onPress: () => navigation.dispatch(data.action),
},
]
);
}
});

return (
<View style={styles.content}>
<TextInput
autoFocus
style={styles.input}
value={text}
placeholder="Type something…"
onChangeText={setText}
/>
</View>
);
};
Snack 上尝试

在内部,该 Hook 使用 beforeRemove 事件来阻止屏幕被移除。每当由于导航操作而移除屏幕时,都会触发此事件。

局限性

使用 usePreventRemove Hook 时,需要注意一些局限性。它在由于导航状态更改而移除屏幕时触发。例如

  • 用户按下了堆栈中屏幕的返回按钮。
  • 用户执行了滑动返回手势。
  • 某些 action(例如 popreset)被 dispatch,从而从状态中移除了屏幕。

如果屏幕未被移除,它不会阻止屏幕失去焦点。例如

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

当用户由于不受导航状态控制的操作而退出屏幕时,它也不会阻止屏幕被移除

  • 用户关闭应用程序(例如,通过按下主屏幕上的返回按钮、关闭浏览器中的标签页、从应用切换器中关闭等)。你可以额外使用 Android 上的 hardwareBackPress 事件、Web 上的 beforeunload 事件等来处理其中一些情况。有关更多详细信息,请参阅 阻止用户离开应用
  • 由于条件渲染或父组件被卸载,屏幕被卸载。

用户体验考虑

总的来说,我们建议谨慎使用此 Hook。更好的方法是将未保存的数据持久化到 AsyncStorage 或类似的持久存储中,并在用户返回屏幕时提示恢复它。

这样做有几个好处

  • 如果应用程序关闭或意外崩溃,此方法仍然有效。
  • 这对用户的干扰较小,因为他们仍然可以导航离开屏幕去检查某些内容,并在返回时不会丢失数据。