How to detect user leaving screen in React Native and act accordingly

Viewed 2143

How to detect user leaving a screen in React Native and act accordingly ?

For an example when user tries to leave current screen alert should popup and say You have unsaved changes, are you sure you want to leave?. If yes user can leave the screen, if no user should be in same screen.

import { useFocusEffect } from '@react-navigation/native';
import {Alert} from 'react-native'

const Profile = (props) => {
  useFocusEffect(
    React.useCallback(() => {
      // Do something when the screen is focused

      return () => {
        // Do something when the screen is unfocused
        // Useful for cleanup functions
        Alert.alert(
          'Want to leave',
          'You have unsaved changes, are you sure you want to leave?',
          [
            {
              text: 'yes',
              onPress: () => {
                // should leave to the screen user has navigate
              },
            },
            { text: 'no', onPress: () => null },
          ],
          true
        )
      };
    }, [])
  );

  return <ProfileContent />;
}

export default Profile

Currently I'm facing few problems with this code.

  1. Alert will popup once user already navigate to selected navigation screen. But I want Alert to be popup before user navigate to the selected screen.

  2. If user selected no, User should be remain in the same screen.

Is there a way to achieve these things ?

Thanks.

Answer

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}
    />
  );
}

for more information refer: https://reactnavigation.org/docs/preventing-going-back/

This will prevent user to going back from one screen to another. But this does not prevent tab navigation because screen does not get removed.

prevent from tab navigation

<Tab.Screen
                    name={'search'}
                    component={SearchNavigator}
                    options={{
                      tabBarIcon: ({ focused, color }) => (
                        <View>
                          <Icon
                            name='search1'
                            color={
                              focused
                                ? 'black'
                                : 'white'
                            }
                            size={25}
                          />
                        </View>
                      ),
                    }}
                    listeners={{
                      tabPress: (e) => {
                        if (true) {
                          // Prevent default action
                          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: () =>
                                  navigationRef.current?.navigate(
                                    'search',
                                    {}
                                  ),
                              },
                            ]
                          )
                        }
                      },
                    }}
                  />

You can add listener tabPress like above code and provide an Alert.

0 Answers
Related