usePreventRemove
usePreventRemove
钩子允许你阻止用户离开屏幕。例如,如果有未保存的更改,你可能希望在用户离开之前显示确认对话框。
¥The usePreventRemove
hook allows you to prevent the user from leaving a screen. For example, if there are unsaved changes, you might want to show a confirmation dialog before the user can navigate away.
钩子需要 2 个参数:
¥The hook takes 2 parameters:
-
preventRemove
:一个布尔值,表示是否防止屏幕被移除。¥
preventRemove
: A boolean value indicating whether to prevent the screen from being removed. -
callback
:当防止删除时将调用的函数。这可用于显示确认对话框。¥
callback
: A function that will be called when the removal is prevented. This can be used to show a confirmation dialog.
回调接收带有触发屏幕移除的 action
的 data
对象。你可以在确认后再次调度此操作,或检查操作对象以确定要执行的操作。
¥The callback receives a data
object with the action
that triggered the removal of the screen. You can dispatch this action again after confirmation, or check the action object to determine what to do.
示例:
¥Example:
- Static
- Dynamic
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>
);
};
const EditTextScreen = () => {
const navigation = useNavigation();
const [text, setText] = React.useState('');
const hasUnsavedChanges = Boolean(text);
usePreventRemove(hasUnsavedChanges, ({ data }) => {
if (Platform.OS === 'web') {
// Alert is not supported on web, so we can use confirm
const discard = confirm(
'You have unsaved changes. Discard them and leave the screen?'
);
if (discard) {
navigation.dispatch(data.action);
}
} else {
// Prompt the user before leaving the screen
Alert.alert(
'Discard changes?',
'You have unsaved changes. Discard them and leave the screen?',
[
{
text: "Don't leave",
style: 'cancel',
onPress: () => {
// Do nothingP
},
},
{
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>
);
};
在内部,钩子使用 beforeRemove
事件来防止屏幕被移除。每当由于导航操作而删除屏幕时,都会触发此事件。
¥Internally, the hook uses the beforeRemove
event to prevent the screen from being removed. This event is triggered whenever a screen is being removed due to a navigation action.
局限性
¥Limitations
使用 usePreventRemove
钩子时需要注意几个限制。它仅在由于导航状态更改而移除屏幕时触发。例如:
¥There are a couple of limitations to be aware of when using the usePreventRemove
hook. It is only triggered whenever a screen is being removed due to a navigation state change. For example:
-
用户按下了堆栈中屏幕上的后退按钮。
¥The user pressed the back button on a screen in a stack.
-
用户执行了向后滑动手势。
¥The user performed a swipe-back gesture.
-
调度一些操作(例如
pop
或reset
),将屏幕从状态中删除。¥Some action such as
pop
orreset
was dispatched which removes the screen from the state.
如果屏幕未被移除,它不会阻止屏幕失去焦点。例如:
¥It does not prevent a screen from being unfocused if it's not being removed. For example:
-
用户将一个新屏幕推到屏幕顶部,监听器位于堆栈中。
¥The user pushed a new screen on top of the screen with the listener in a stack.
-
用户从一个选项卡/抽屉式屏幕导航到另一选项卡/抽屉式屏幕。
¥The user navigated from one tab/drawer screen to another tab/drawer screen.
当用户由于导航状态未控制的操作而退出屏幕时,它也不会阻止屏幕被移除:
¥It also does not prevent a screen from being removed when the user is exiting the screen due to actions not controlled by the navigation state:
-
用户关闭应用(例如,通过按下主屏幕上的后退按钮、关闭浏览器中的选项卡、从应用切换器关闭它等)。你还可以在 Android 上使用
hardwareBackPress
事件,在 Web 上使用beforeunload
事件等来处理其中一些情况。详细信息请参见 防止用户离开应用。¥The user closes the app (e.g. by pressing the back button on the home screen, closing the tab in the browser, closing it from the app switcher etc.). You can additionally use
hardwareBackPress
event on Android,beforeunload
event on the Web etc. to handle some of these cases. See Prevent the user from leaving the app for more details. -
由于条件渲染或父组件被卸载,屏幕被卸载。
¥A screen gets unmounted due to conditional rendering, or due to a parent component being unmounted.
UX 注意事项
¥UX considerations
通常,我们建议谨慎使用此钩子。更好的方法是将未保存的数据持久化到 AsyncStorage
或类似的持久存储中,并在用户返回屏幕时提示恢复。
¥Generally, we recommend using this hook sparingly. A better approach is to persist the unsaved data into AsyncStorage
or similar persistent storage and prompt to restore it when the user returns to the screen.
这样做有几个好处:
¥Doing so has several benefits:
-
如果应用关闭或意外崩溃,此方法仍然有效。
¥This approach still works if the app is closed or crashes unexpectedly.
-
它对用户的干扰较小,因为他们仍然可以离开屏幕去检查某些内容并返回而不会丢失数据。
¥It's less intrusive to the user as they can still navigate away from the screen to check something and return without losing the data.