Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Back Button React native exit app

I have put android back button exit the app functionality in my react native app in my home screen. But when I press android back button on other screens then also it is getting called.

componentDidMount() {

    if (Platform.OS == "android") {
        BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);                           
  }
    this._setupGoogleSignin();           
    this._getUserDetails();
    const { navigate } = this.props.navigation;
    console.log("object url is", this.state.postsArray[0].url);

}

handleBackButton = () => {               
    Alert.alert(
        'Exit App',
        'Exiting the application?', [{
            text: 'Cancel',
            onPress: () => console.log('Cancel Pressed'),
            style: 'cancel'
        }, {
            text: 'OK',
            onPress: () => BackHandler.exitApp()
        }, ], {
            cancelable: false
        }
     )
     return true;
   }
componentWillUnmount() {
    BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
  }
like image 563
Paras Watts Avatar asked Sep 21 '17 10:09

Paras Watts


People also ask

How do I exit app React Native?

React Native provides the BackHandler component to handle exit functionality in android. when you call BackHandler. exitApp(); app will close but it will remain in android's recent tab.

How do I manage the back button in React Native?

To handle the Android Back Button Press in the React Native we have to register the hardwareBackPress event listener with a callback function, which will be called after pressing the Back Button.

How do I exit the react navigation app?

Exit app when back button is pressed twice in React Native.

How do you handle the back button in react navigation?

By default React Navigation will handle the Android back button for you, however we'll need to override the defaults. If you're at the top of the stack and press the android back button the application will close. If you've navigated within the stack anywhere then the screen will pop.


6 Answers

If your HomeScreen is still mounted when you navigate to other screens or while unmounting the HomeScreen if you don't remove the EventListener it will be still called.

You should clear the EventListener on navigate or unmount,

onButtonPress = () => {
  BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
  // then navigate
  navigate('NewScreen');
}

handleBackButton = () => {
 Alert.alert(
     'Exit App',
     'Exiting the application?', [{
         text: 'Cancel',
         onPress: () = > console.log('Cancel Pressed'),
         style: 'cancel'
     }, {
         text: 'OK',
         onPress: () = > BackHandler.exitApp()
     }, ], {
         cancelable: false
     }
  )
  return true;
} 

componentDidMount() {
  BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
}

componentWillUnmount() {
  BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
}
like image 51
bennygenel Avatar answered Oct 10 '22 10:10

bennygenel


If you don't want the Alert message to appear in other component/screen but only in one specific component/screen, you can follow this.

import { withNavigationFocus } from 'react-navigation';

class TestComponent extends Component {
  componentWillMount() {
    BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
  }

  componentWillUnmount() {
    BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
  }

  handleBackButton = () => {
    if (this.props.isFocused) {
      Alert.alert(
        'Exit App',
        'Exiting the application?',
        [
          {
            text: 'Cancel',
            onPress: () => console.log('Cancel Pressed'),
            style: 'cancel'
          },
          {
            text: 'OK',
            onPress: () => BackHandler.exitApp()
          }
        ],
        {
          cancelable: false
        }
      );
      return true;
    }
  };
} 

export default withNavigationFocus(TestComponent );

The BackHandler that will show an Alert message will only work in TestComponent

like image 23
zurc0405 Avatar answered Oct 10 '22 10:10

zurc0405


We can add subscriptions for didfocus inside our main App Container.We can add our logic to check for button tapped with a static variable.

import {  Alert,  BackHandler,  ToastAndroid } from 'react-native';
import {  StackActions } from 'react-navigation';
import { Toast } from 'native-base';
// common statless class variable.
let backHandlerClickCount = 0;

class App extends React.Component {
    constructor(props) {
      super(props);
      // add listener to didFocus
      this._didFocusSubscription = props.navigation.addListener('didFocus', payload =>
        BackHandler.addEventListener('hardwareBackPress', () => this.onBackButtonPressAndroid(payload)));
    }

    // remove listener on unmount 
    componentWillUnmount() {
      if (this._didFocusSubscription) {
        this._didFocusSubscription.remove();
      }
    }

    onBackButtonPressAndroid = () => {
      const shortToast = message => {
        // ToastAndroid.showWithGravityAndOffset(
        //     message,
        //     ToastAndroid.SHORT,
        //     ToastAndroid.BOTTOM,
        //     25,
        //     50
        // );

        // ios & android
        Toast.show({
            text: message,
            type: 'warning',
            position: 'top',
            duration: 3000,
        });
        }

        const {
          clickedPosition
        } = this.state;
        backHandlerClickCount += 1;
        if ((clickedPosition !== 1)) {
          if ((backHandlerClickCount < 2)) {
            shortToast('Press again to quit the application!');
          } else {
            BackHandler.exitApp();
          }
        }

        // timeout for fade and exit
        setTimeout(() => {
          backHandlerClickCount = 0;
        }, 2000);

        if (((clickedPosition === 1) &&
            (this.props.navigation.isFocused()))) {
          Alert.alert(
            'Exit Application',
            'Do you want to quit application?', [{
              text: 'Cancel',
              onPress: () => console.log('Cancel Pressed'),
              style: 'cancel'
            }, {
              text: 'OK',
              onPress: () => BackHandler.exitApp()
            }], {
              cancelable: false
            }
          );
        } else {
          this.props.navigation.dispatch(StackActions.pop({
            n: 1
          }));
        }
        return true;
      }

    }
like image 37
Mukundhan Avatar answered Oct 10 '22 10:10

Mukundhan


Just adding to other answers

If you are using '@react-navigation/native' then setting eventListner on backButton will work even when you have navigated to child screens. To overcome this set eventListner on focus rather than with componentDidMount() and remove it when blur event occurs on screen.

Learn more about react-navigation events here

export class sampleScreen extends Component {
constructor(props) {
    super(props);
    this.state = {
        foo: '',
        bar: '',
    };

    this._unsubscribeSiFocus = this.props.navigation.addListener('focus', e => {
        console.warn('focus signIn');
        BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
    });
    this._unsubscribeSiBlur = this.props.navigation.addListener('blur', e => {
        console.warn('blur signIn');
        BackHandler.removeEventListener(
            'hardwareBackPress',
            this.handleBackButton,
        );
    });

    onButtonPress = () => {
        BackHandler.removeEventListener(
            'hardwareBackPress',
            this.handleBackButton,
        );
    };
}

handleBackButton = () => {
    Alert.alert(
        'Exit App',
        'Exiting the application?',
        [{
                text: 'Cancel',
                onPress: () => console.log('Cancel Pressed'),
                style: 'cancel',
            },
            {
                text: 'OK',
                onPress: () => BackHandler.exitApp(),
            },
        ], {
            cancelable: false,
        },
    );
    return true;
};

componentDidMount() {
    // BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
}

componentWillUnmount() {
    this._unsubscribeSiFocus();
    this._unsubscribeSiBlur();
    BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
}

}

like image 40
Tushar Gautam Avatar answered Oct 10 '22 10:10

Tushar Gautam


Guyz please do understand it might not only be the problem with react native. Be careful while integrating it with firebase. The recent firebase version has the problem of integrating back button in react-native apps!! Please downgrade the firebase version to firebase-version @5.0.3 and then recheck whether it works or not! I had the same issue and was worried for days. I finally downgraded to @5.0.3 version and now the back button works perfectly fine! You may downgrade to lower versions if still facing the problem.

like image 39
Rishav Kumar Avatar answered Oct 10 '22 09:10

Rishav Kumar


You can always dynamically modify what the callback function for the BackHandler.addEventListener is based on the current scene (using react-native-router-flux makes this easy).

import { Actions } from 'react-native-router-flux'

handleBackPress = () => {
 switch (Actions.currentScene) {
   case 'home':
     BackHandler.exitApp()
     break

   default: Actions.pop()
 }

 return true
}

The full gist can be found here: https://gist.github.com/omeileo/f05a068557e9f0a2d8a24ecccd2f3177

like image 42
Jase-Omeileo West Avatar answered Oct 10 '22 10:10

Jase-Omeileo West