Handling back button in React Native, Navigator on Android

前端 未结 6 800
旧巷少年郎
旧巷少年郎 2021-02-01 14:45

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

相关标签:
6条回答
  • 2021-02-01 15:25

    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';
    
    0 讨论(0)
  • 2021-02-01 15:28

    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
    }
    
    0 讨论(0)
  • 2021-02-01 15:31

    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.

    0 讨论(0)
  • 2021-02-01 15:37

    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; }} />
    
    0 讨论(0)
  • 2021-02-01 15:37

    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>
            );
        }
    }
    
    0 讨论(0)
  • 2021-02-01 15:41

    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}}
      ...
    
    0 讨论(0)
提交回复
热议问题