Skip to main content
Version: 7.x

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.

The hook takes 2 parameters:

  • preventRemove: A boolean value indicating whether to prevent the screen from being removed.
  • callback: A function that will be called when the removal is prevented. This can be used to show a confirmation dialog.

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:

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>
);
};
Try on Snack

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

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.
  • Some action such as pop or reset 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:

UX considerations

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.