0

I am trying to create a small react native app and in that app, I have created some screens. On a particular screen, I want to disable the system back button and I did that but I want to create a logic on that same screen that if the user taps twice then app will be closed.

My screen

import React, {Component, useEffect} from 'react';
import {StyleSheet, Text, View, Button, BackHandler, Alert} from 'react-native';

export default function HomeScreen({navigation}) {
  useEffect(() => {
    BackHandler.addEventListener('hardwareBackPress', () => true);
    return () =>
      BackHandler.removeEventListener('hardwareBackPress', () => true);
  }, []);

  return (
    <View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
      <Text>Home Screen</Text>
      <Button
        title="Go to Other Screen"
        onPress={() => navigation.navigate('Employees')}
      />
    </View>
  );
}

But there is one more problem as well, This code is disabling back button on every screen.

5eb
  • 14,798
  • 5
  • 21
  • 65
Mohit Chandel
  • 1,838
  • 10
  • 31

2 Answers2

1

Based on the accepted answer (Bas van der Linden). I created this useful hook:

THE HOOK

const usePreventCloseApp = (onBeforeCloseApp) => {
    const [backPressedCount, setBackPressedCount] = useState(0);

    useFocusEffect(
        useCallback(() => {
            const sub = BackHandler.addEventListener(
                'hardwareBackPress',
                () => {
                    if (onBeforeCloseApp) {
                        onBeforeCloseApp(() => setBackPressedCount(2));
                    } else {
                        setBackPressedCount((pre) => {
                            if (pre === 0) {
                                ToastAndroid.show('Press again to exit', 1000);
                                setTimeout(() => setBackPressedCount(0), 1000);
                            }
                            return pre + 1;
                        });
                    }
                    return true;
                },
            );
            return sub.remove;
        }, [onBeforeCloseApp]),
    );

    useEffect(() => {
        if (backPressedCount === 2) {
            BackHandler.exitApp();
        }
    }, [backPressedCount]);

    return {
        closeApp: () => setBackPressedCount(2),
    };
};

USAGE

Display default toast "Press again to exit"

const { closeApp } = usePreventCloseApp();

With custom callback

usePreventCloseApp((closeApp) => {
     Alert.alert('Close App', 'Are you sure want to close app?', [
         {
             text: 'Cancel',
             style: 'cancel',
         },
         {
             text: 'Close App',
             style: 'destructive',
             onPress: closeApp,
         },
     ]);
 });
Hoang Tran
  • 11
  • 3
0

For the exiting on pressing the hardware button twice part you could create some state, increment it and when it equals 2 exit the app using Backhandler's exitApp function.

If you only want the Backhandler event code to be active for the HomeScreen component you could use useFocusEffect

React Navigation provides a hook that runs an effect when the screen comes into focus and cleans it up when it goes out of focus

Source

function HomeScreen({navigation}) {
  const [backPressedCount, setBackPressedCount] = useState(0);

  useFocusEffect(
    useCallback(() => {
      BackHandler.addEventListener('hardwareBackPress', () => {
        setBackPressedCount((backPressedCount) => backPressedCount + 1);
        return true;
      });
      return () =>
        BackHandler.removeEventListener('hardwareBackPress', () => true);
    }, []),
  );

  useEffect(() => {
    if (backPressedCount === 2) {
      BackHandler.exitApp();
    }
  }, [backPressedCount]);

  return (
    <View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
      <Text>Home Screen</Text>
      <Button
        title="Go to Other Screen"
        onPress={() => navigation.navigate('Employees')}
      />
    </View>
  );
}
5eb
  • 14,798
  • 5
  • 21
  • 65