Reputation: 2665
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);
}
Upvotes: 30
Views: 63788
Reputation: 1
In case you are looking for Back Press in Functional Components.
useEffect(() => {
BackHandler.addEventListener('hardwareBackPress', handleBackButton);
return () => {
// Anything in here is fired on component unmount.
BackHandler.removeEventListener('hardwareBackPress', handleBackButton);
}
}, [])
onButtonPress = () => {
BackHandler.removeEventListener('hardwareBackPress', handleBackButton);
// then navigate
//navigate('NewScreen');
}
const handleBackButton = () => {
BackHandler.exitApp();
return true;
}
Upvotes: 0
Reputation: 731
if you want to double back press to Exit App
import React, {useEffect} from 'react';
import {BackHandler} from 'react-native';
import {Provider} from 'react-redux';
import Toast from 'react-native-root-toast';
let backHandlerClickCount = 0;
const App = () => {
useEffect(() => {
// back handle exit app
BackHandler.addEventListener('hardwareBackPress', backButtonHandler);
return () => {
BackHandler.removeEventListener('hardwareBackPress', backButtonHandler);
};
}, []);
const backButtonHandler = () => {
const shortToast = message => {
Toast.show(message, {
duration: Toast.durations.LONG,
position: Toast.positions.BOTTOM,
});
}
let backHandlerClickCount;
backHandlerClickCount += 1;
if ((backHandlerClickCount < 2)) {
shortToast('Press again to quit the application');
} else {
BackHandler.exitApp();
}
// timeout for fade and exit
setTimeout(() => {
backHandlerClickCount = 0;
}, 1000);
return true;
}
return (
<Provider store={store}>
....
</Provider>
);
};
export default App;
Upvotes: 2
Reputation: 310
I also had a problem with this issue, but I managed to solve it in this quite simple way. I am using react-navigation 4.4.1.
import React from 'react';
import { BackHandler, ToastAndroid} from 'react-native';
export default class LoginScreen extends React.Component {
state = {
canBeClosed: false
}
componentDidMount() {
BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
}
handleBackButton = () => {
if (this.props.navigation.isFocused()) {
if (this.state.canBeClosed)
return this.state.canBeClosed = false;
else {
setTimeout(() => { this.state.canBeClosed = false }, 3000);
ToastAndroid.show("Press Again To Exit !", ToastAndroid.SHORT);
return this.state.canBeClosed = true
}
}
};
//some code
}
Upvotes: 0
Reputation: 295
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);
}
}
Upvotes: 2
Reputation: 21
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
Upvotes: 1
Reputation: 3457
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;
}
}
Upvotes: 4
Reputation: 77
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
Upvotes: 7
Reputation: 5450
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.
Upvotes: 1
Reputation: 293
BackHandler.addEventListener('hardwareBackPress', function() {
Alert.alert(
'Thoát Khỏi Ứng Dụng',
'Bạn có muốn thoát không?', [{
text: 'Cancel',
onPress: () => console.log('Cancel Pressed'),
style: 'cancel'
}, {
text: 'OK',
onPress: () => BackHandler.exitApp()
}, ], {
cancelable: false
}
)
return true;
})
Upvotes: 0
Reputation: 24660
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);
}
Upvotes: 44