React Navigation 有提供一個 hook usePreventRemove
可以實現這個功能
官方 demo:
import { usePreventRemove } from '@react-navigation/native';
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>
);
};
但如果想要使用自定義的提醒視窗,就需要把 data.action 存在 state 中,才能在其他地方使用
import { useNavigation, usePreventRemove } from '@react-navigation/native';
const EditTextScreen = () => {
const navigation = useNavigation();
const [isModalVisible, setIsModalVisible] = useState(false);
const [pendingAction, setPendingAction] = useState(null);
usePreventRemove(hasUnsavedChanges, ({ data }) => {
setPendingAction(data.action);
setIsModalVisible(true);
});
const handleSave = async () => {
// ...
setIsModalVisible(false);
if (pendingAction) {
navigation.dispatch(pendingAction);
}
};
const handleDiscard = () => {
setIsModalVisible(false);
if (pendingAction) {
navigation.dispatch(pendingAction);
}
};
const handleContinue = () => {
setIsModalVisible(false);
};
return (
<View>
...
<ConfirmModal
isVisible={isModalVisible}
title="儲存為草稿?"
message="儲存為草稿,以便稍後編輯和發佈。"
saveText="儲存"
discardText="不儲存"
continueText="繼續編輯"
onSave={handleSave}
onDiscard={handleDiscard}
onContinue={handleContinue}
/>
</View>
)
}