I have a Navigator
in an Android react native application.
I\'m using navigator.push()
to navigate to a different page. It would seem natural t
Not sure when the API changed but as of react native 0.31 (potentially earlier versions as well) BackAndroid is a component that must be imported from react-native:
import {..., BackAndroid} from 'react-native'
Also be sure to remove the listener on componentWillUnmount:
componentWillUnmount(){
BackAndroid.removeEventListener('hardwareBackPress', () => {
if (this.navigator && this.navigator.getCurrentRoutes().length > 1) {
this.navigator.pop();
return true;
}
return false;
});
}
*UPDATE: In react native 0.44 this module has been renamed to BackHandler
. Navigator
has also been officially deprecated but can still be found here: https://github.com/facebookarchive/react-native-custom-components
import { BackHandler } from 'react-native';
In order to clean the code using my knowledge and previous answers, here is how it should look like:
import { ..., Navigator, BackAndroid } from 'react-native';
componentDidMount() {
BackAndroid.addEventListener('hardwareBackPress', this.handleBack);
}
componentWillUnmount() {
//Forgetting to remove the listener will cause pop executes multiple times
BackAndroid.removeEventListener('hardwareBackPress', this.handleBack);
}
handleBack() {
if (this.navigator && this.navigator.getCurrentRoutes().length > 1){
this.navigator.pop();
return true; //avoid closing the app
}
return false; //close the app
}
Yes, you have to handle the back button yourself. I think the main reason for this is you may want to do different things with the back button instead of just moving back through the stack. I don't know if there are plans to incorporate back button functionality in the future though.
In addition to answer above, handling code should be something like this
var navigator;
React.BackAndroid.addEventListener('hardwareBackPress', () => {
if (navigator && navigator.getCurrentRoutes().length > 1) {
navigator.pop();
return true;
}
return false;
});
in render code:
<Navigator ref={(nav) => { navigator = nav; }} />
I have created a GitHub repo that will provide you a sample project of how to handle the Android Back Button.
You can clone / download the repo at:
Android Back Button Sample Project
But here are some sample codes on how I handle the android back button
The following code is for my initial screen when user starts my app. Pressing the back button button here would show an alert of which will ask the user whether the user would like to leave the app.
import React, {Component} from 'react';
import {View,Text,Button,BackHandler,Alert} from 'react-native';
import {NavigationActions} from 'react-navigation';
export default class InitScreen extends Component {
_focusDoneSubscribe;//declaring variable that will be listener for the back button when in focus
_blurGoingSubscribe;//declaring variable that will be listener for the back button when blur
//the following will remove the navigation bar at the top
static navigationOptions = {
header: null,
title: 'Welcome',
};
constructor(props)
{
super(props);
this._focusDoneSubscribe = props.navigation.addListener('didFocus', payload =>
BackHandler.addEventListener('hardwareBackPress', this.onBackButtonPressAndroid)
);//this assigns the listener
}
//functions to handle back button events
componentDidMount()
{
this._blurGoingSubscribe = this.props.navigation.addListener('willBlur', payload =>
BackHandler.removeEventListener('hardwareBackPress', this.onBackButtonPressAndroid)
);
}
onBackButtonPressAndroid = () => {
Alert.alert(
'Exiting App',
'Confirm quitting the app?',
[
{text: 'CANCEL', style: 'cancel'},
{text: 'STOP ASKING AND QUIT', onPress: () => BackHandler.exitApp()}
],
{cancelable: false},
);
return true;
};
componentWillUnmount()
{
this._focusDoneSubscribe && this._focusDoneSubscribe.remove();
this._blurGoingSubscribe && this._blurGoingSubscribe.remove();
}
//actual render
render(){
const { navigate } = this.props.navigation;
return (
<View style={{alignItems: 'center'}}>
<View style={{height: 100,justifyContent: 'center',alignItems: 'center'}}>
<Text style={{fontSize: 20}}>Navigation BackHandler Tutorial</Text>
<Text style={{fontSize: 20}}>Initial Screen</Text>
</View>
<View style={{flexDirection: 'column', justifyContent: 'space-between', height: 100}}>
<Button
title="SCREEN ONE"
onPress={() => {this.props.navigation.push('One')}}
/>
<Button
title="SCREEN TWO"
onPress={() => {this.props.navigation.push('Two')}}
/>
</View>
</View>
);
}
}
The following code is a screen for which when the user presses the back button, it go back the previous screen:
import React, {Component} from 'react';
import {View,Text,Button,BackHandler} from 'react-native';//declaring variable that will be listener for the back button when in focus
import {NavigationActions} from 'react-navigation';//declaring variable that will be listener for the back button when blur
export default class ScreenOne extends Component {
_focusDoneSubscribe;
_blurGoingSubscribe;
//the following will remove the navigation bar at the top
static navigationOptions = {
header: null,
title: 'ONE',
};
constructor(props)
{
super(props);
this._focusDoneSubscribe = props.navigation.addListener('didFocus', payload =>
BackHandler.addEventListener('hardwareBackPress', this.onBackButtonPressAndroid)
);//this assigns the listener
}
//functions to handle back button events
componentDidMount()
{
this._blurGoingSubscribe = this.props.navigation.addListener('willBlur', payload =>
BackHandler.removeEventListener('hardwareBackPress', this.onBackButtonPressAndroid)
);
}
onBackButtonPressAndroid = () => {
this.props.navigation.goBack();
return true;
};
componentWillUnmount()
{
this._focusDoneSubscribe && this._focusDoneSubscribe.remove();
this._blurGoingSubscribe && this._blurGoingSubscribe.remove();
}
//actual render
render(){
const { navigate } = this.props.navigation;
return (
<View style={{alignItems: 'center'}}>
<View style={{height: 100,justifyContent: 'center',alignItems: 'center'}}>
<Text style={{fontSize: 20}}>Navigation BackHandler Tutorial</Text>
<Text style={{fontSize: 20}}>SCREEN ONE</Text>
</View>
</View>
);
}
}
Don't forget bind [this]
The correct answer should be:
export default class MyPage extends Component {
constructor(props) {
super(props)
this.navigator = null;
this.handleBack = (() => {
if (this.navigator && this.navigator.getCurrentRoutes().length > 1){
this.navigator.pop();
return true; //avoid closing the app
}
return false; //close the app
}).bind(this) //don't forget bind this, you will remember anyway.
}
componentDidMount() {
BackAndroid.addEventListener('hardwareBackPress', this.handleBack);
}
componentWillUnmount() {
BackAndroid.removeEventListener('hardwareBackPress', this.handleBack);
}
render() {
return (
<Navigator
ref={navigator => {this.navigator = navigator}}
...