React Native - BackHandler with Alert









up vote
1
down vote

favorite












I'm attempting to override the back button on a screen with a prompt to Logout. See the following:



import React, Component from "react";
import Alert, BackHandler from "react-native";

export default class Dashboard extends Component

constructor(props)
super(props);


componentDidMount()

BackHandler.addEventListener("hardwareBackPress",this.handleBackPress);


componentWillUnmount()
BackHandler.removeEventListener("hardwareBackPress", this.handleBackPress);


handleBackPress()
Alert.alert(
"Logout",
"Are you sure you want to logout?",
[

text: "Cancel",
onPress: () =>
console.log("Cancel Pressed");
,
style: "cancel"
,
text: "Logout", onPress: () => this.handleLogout()
],
cancelable: false
);


handleLogout()
this.props.navigation.navigate("Login");




As you can see, on mounting change, I'm binding and unbinding "hardwareBackPress" to this.handleBackPress. Note, I have to use .bind(this), otherwise I get




_this2.handleLogout is not a function




when I press the Logout in the Alert. Expected functionality is:



  • Back button is pressed

  • Functionality disabled (doesn't navigate)

  • Alert is displayed

  • Ok is pressed

  • Navigates back

  • Back button on previous screen has default action

But what actually happens is:



  • Back button is pressed

  • Navigates back

  • Alert is displayed

  • (Subsequent steps don't matter)

I noticed I don't have return true; anywhere in my handleBackPress(), so I added that:



handleBackPress() 
Alert.alert(
"Logout",
"Are you sure you want to logout?",
[

text: "Cancel",
onPress: () =>
console.log("Cancel Pressed");
,
style: "cancel"
,

text: "Logout",
onPress: () =>
return this.handleLogout();


],
cancelable: false
);

return true;



But what happens now is:



  • Back button is pressed

  • Functionality disabled (doesn't navigate)

  • Alert is displayed

  • Ok is pressed

  • Navigates back

  • Back button press on previous screen results in Alert being displayed

I have verified that componentDidUnmount() is called, but it doesn't seem to have removed the event listener.



Has anyone encountered this issue before? For now, I've just resorted to globally disabling the back button by adding this handler at the entry point of the app, but that's not a long-term solution.



Edit: I noticed there's a lifecycle alternative, so I tried implementing that:



componentDidMount() 
this.backHandler = BackHandler.addEventListener("hardwareBackPress", () =>
Alert.alert("Logout", "Are you sure you want to logout?", [ text: "Cancel", onPress: () => , style: "cancel" , text: "Logout", onPress: () => this.handleLogout() ], cancelable: false );
return true;
);


componentWillUnmount()
this.backHandler.remove();



And while this makes it work (somehow), it has yet another side-effect. As soon as I navigate forward (which doesn't trigger componentDidUnmount(), due to stacked navigation), and navigate back, the back button behaves as such:



  • Back button is pressed

  • Functionality disabled (doesn't navigate)

  • Alert doesn't show up

The screen I'm navigating forward to has it's back button overridden, and seems to not play well with this alternative lifecycle. Will attempt to implement different approach on all subsequent screens; see if it behaves properly then.










share|improve this question



























    up vote
    1
    down vote

    favorite












    I'm attempting to override the back button on a screen with a prompt to Logout. See the following:



    import React, Component from "react";
    import Alert, BackHandler from "react-native";

    export default class Dashboard extends Component

    constructor(props)
    super(props);


    componentDidMount()

    BackHandler.addEventListener("hardwareBackPress",this.handleBackPress);


    componentWillUnmount()
    BackHandler.removeEventListener("hardwareBackPress", this.handleBackPress);


    handleBackPress()
    Alert.alert(
    "Logout",
    "Are you sure you want to logout?",
    [

    text: "Cancel",
    onPress: () =>
    console.log("Cancel Pressed");
    ,
    style: "cancel"
    ,
    text: "Logout", onPress: () => this.handleLogout()
    ],
    cancelable: false
    );


    handleLogout()
    this.props.navigation.navigate("Login");




    As you can see, on mounting change, I'm binding and unbinding "hardwareBackPress" to this.handleBackPress. Note, I have to use .bind(this), otherwise I get




    _this2.handleLogout is not a function




    when I press the Logout in the Alert. Expected functionality is:



    • Back button is pressed

    • Functionality disabled (doesn't navigate)

    • Alert is displayed

    • Ok is pressed

    • Navigates back

    • Back button on previous screen has default action

    But what actually happens is:



    • Back button is pressed

    • Navigates back

    • Alert is displayed

    • (Subsequent steps don't matter)

    I noticed I don't have return true; anywhere in my handleBackPress(), so I added that:



    handleBackPress() 
    Alert.alert(
    "Logout",
    "Are you sure you want to logout?",
    [

    text: "Cancel",
    onPress: () =>
    console.log("Cancel Pressed");
    ,
    style: "cancel"
    ,

    text: "Logout",
    onPress: () =>
    return this.handleLogout();


    ],
    cancelable: false
    );

    return true;



    But what happens now is:



    • Back button is pressed

    • Functionality disabled (doesn't navigate)

    • Alert is displayed

    • Ok is pressed

    • Navigates back

    • Back button press on previous screen results in Alert being displayed

    I have verified that componentDidUnmount() is called, but it doesn't seem to have removed the event listener.



    Has anyone encountered this issue before? For now, I've just resorted to globally disabling the back button by adding this handler at the entry point of the app, but that's not a long-term solution.



    Edit: I noticed there's a lifecycle alternative, so I tried implementing that:



    componentDidMount() 
    this.backHandler = BackHandler.addEventListener("hardwareBackPress", () =>
    Alert.alert("Logout", "Are you sure you want to logout?", [ text: "Cancel", onPress: () => , style: "cancel" , text: "Logout", onPress: () => this.handleLogout() ], cancelable: false );
    return true;
    );


    componentWillUnmount()
    this.backHandler.remove();



    And while this makes it work (somehow), it has yet another side-effect. As soon as I navigate forward (which doesn't trigger componentDidUnmount(), due to stacked navigation), and navigate back, the back button behaves as such:



    • Back button is pressed

    • Functionality disabled (doesn't navigate)

    • Alert doesn't show up

    The screen I'm navigating forward to has it's back button overridden, and seems to not play well with this alternative lifecycle. Will attempt to implement different approach on all subsequent screens; see if it behaves properly then.










    share|improve this question

























      up vote
      1
      down vote

      favorite









      up vote
      1
      down vote

      favorite











      I'm attempting to override the back button on a screen with a prompt to Logout. See the following:



      import React, Component from "react";
      import Alert, BackHandler from "react-native";

      export default class Dashboard extends Component

      constructor(props)
      super(props);


      componentDidMount()

      BackHandler.addEventListener("hardwareBackPress",this.handleBackPress);


      componentWillUnmount()
      BackHandler.removeEventListener("hardwareBackPress", this.handleBackPress);


      handleBackPress()
      Alert.alert(
      "Logout",
      "Are you sure you want to logout?",
      [

      text: "Cancel",
      onPress: () =>
      console.log("Cancel Pressed");
      ,
      style: "cancel"
      ,
      text: "Logout", onPress: () => this.handleLogout()
      ],
      cancelable: false
      );


      handleLogout()
      this.props.navigation.navigate("Login");




      As you can see, on mounting change, I'm binding and unbinding "hardwareBackPress" to this.handleBackPress. Note, I have to use .bind(this), otherwise I get




      _this2.handleLogout is not a function




      when I press the Logout in the Alert. Expected functionality is:



      • Back button is pressed

      • Functionality disabled (doesn't navigate)

      • Alert is displayed

      • Ok is pressed

      • Navigates back

      • Back button on previous screen has default action

      But what actually happens is:



      • Back button is pressed

      • Navigates back

      • Alert is displayed

      • (Subsequent steps don't matter)

      I noticed I don't have return true; anywhere in my handleBackPress(), so I added that:



      handleBackPress() 
      Alert.alert(
      "Logout",
      "Are you sure you want to logout?",
      [

      text: "Cancel",
      onPress: () =>
      console.log("Cancel Pressed");
      ,
      style: "cancel"
      ,

      text: "Logout",
      onPress: () =>
      return this.handleLogout();


      ],
      cancelable: false
      );

      return true;



      But what happens now is:



      • Back button is pressed

      • Functionality disabled (doesn't navigate)

      • Alert is displayed

      • Ok is pressed

      • Navigates back

      • Back button press on previous screen results in Alert being displayed

      I have verified that componentDidUnmount() is called, but it doesn't seem to have removed the event listener.



      Has anyone encountered this issue before? For now, I've just resorted to globally disabling the back button by adding this handler at the entry point of the app, but that's not a long-term solution.



      Edit: I noticed there's a lifecycle alternative, so I tried implementing that:



      componentDidMount() 
      this.backHandler = BackHandler.addEventListener("hardwareBackPress", () =>
      Alert.alert("Logout", "Are you sure you want to logout?", [ text: "Cancel", onPress: () => , style: "cancel" , text: "Logout", onPress: () => this.handleLogout() ], cancelable: false );
      return true;
      );


      componentWillUnmount()
      this.backHandler.remove();



      And while this makes it work (somehow), it has yet another side-effect. As soon as I navigate forward (which doesn't trigger componentDidUnmount(), due to stacked navigation), and navigate back, the back button behaves as such:



      • Back button is pressed

      • Functionality disabled (doesn't navigate)

      • Alert doesn't show up

      The screen I'm navigating forward to has it's back button overridden, and seems to not play well with this alternative lifecycle. Will attempt to implement different approach on all subsequent screens; see if it behaves properly then.










      share|improve this question















      I'm attempting to override the back button on a screen with a prompt to Logout. See the following:



      import React, Component from "react";
      import Alert, BackHandler from "react-native";

      export default class Dashboard extends Component

      constructor(props)
      super(props);


      componentDidMount()

      BackHandler.addEventListener("hardwareBackPress",this.handleBackPress);


      componentWillUnmount()
      BackHandler.removeEventListener("hardwareBackPress", this.handleBackPress);


      handleBackPress()
      Alert.alert(
      "Logout",
      "Are you sure you want to logout?",
      [

      text: "Cancel",
      onPress: () =>
      console.log("Cancel Pressed");
      ,
      style: "cancel"
      ,
      text: "Logout", onPress: () => this.handleLogout()
      ],
      cancelable: false
      );


      handleLogout()
      this.props.navigation.navigate("Login");




      As you can see, on mounting change, I'm binding and unbinding "hardwareBackPress" to this.handleBackPress. Note, I have to use .bind(this), otherwise I get




      _this2.handleLogout is not a function




      when I press the Logout in the Alert. Expected functionality is:



      • Back button is pressed

      • Functionality disabled (doesn't navigate)

      • Alert is displayed

      • Ok is pressed

      • Navigates back

      • Back button on previous screen has default action

      But what actually happens is:



      • Back button is pressed

      • Navigates back

      • Alert is displayed

      • (Subsequent steps don't matter)

      I noticed I don't have return true; anywhere in my handleBackPress(), so I added that:



      handleBackPress() 
      Alert.alert(
      "Logout",
      "Are you sure you want to logout?",
      [

      text: "Cancel",
      onPress: () =>
      console.log("Cancel Pressed");
      ,
      style: "cancel"
      ,

      text: "Logout",
      onPress: () =>
      return this.handleLogout();


      ],
      cancelable: false
      );

      return true;



      But what happens now is:



      • Back button is pressed

      • Functionality disabled (doesn't navigate)

      • Alert is displayed

      • Ok is pressed

      • Navigates back

      • Back button press on previous screen results in Alert being displayed

      I have verified that componentDidUnmount() is called, but it doesn't seem to have removed the event listener.



      Has anyone encountered this issue before? For now, I've just resorted to globally disabling the back button by adding this handler at the entry point of the app, but that's not a long-term solution.



      Edit: I noticed there's a lifecycle alternative, so I tried implementing that:



      componentDidMount() 
      this.backHandler = BackHandler.addEventListener("hardwareBackPress", () =>
      Alert.alert("Logout", "Are you sure you want to logout?", [ text: "Cancel", onPress: () => , style: "cancel" , text: "Logout", onPress: () => this.handleLogout() ], cancelable: false );
      return true;
      );


      componentWillUnmount()
      this.backHandler.remove();



      And while this makes it work (somehow), it has yet another side-effect. As soon as I navigate forward (which doesn't trigger componentDidUnmount(), due to stacked navigation), and navigate back, the back button behaves as such:



      • Back button is pressed

      • Functionality disabled (doesn't navigate)

      • Alert doesn't show up

      The screen I'm navigating forward to has it's back button overridden, and seems to not play well with this alternative lifecycle. Will attempt to implement different approach on all subsequent screens; see if it behaves properly then.







      javascript android react-native react-navigation






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 9 at 20:14

























      asked Nov 9 at 20:05









      Tim Lewis

      10.2k63358




      10.2k63358






















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          0
          down vote



          accepted










          Using the lifecycle alternative from the Documentation (https://facebook.github.io/react-native/docs/backhandler) seems to handle odd behaviour with Alert and return true;:



          Dashboard.js



          componentDidMount() 
          this.backHandler = BackHandler.addEventListener("hardwareBackPress", () =>
          Alert.alert("Logout", "Are you sure you want to logout?", [ text: "Cancel", onPress: () => , style: "cancel" , text: "Logout", onPress: () => this.handleLogout() ], cancelable: false );
          return true;
          );


          componentWillUnmount()
          this.backHandler.remove();


          handleLogout()
          global.screenName = "Dashboard";
          return this.props.navigation.navigate("Login");



          As long as all subsequent screens that need the back button overridden also use the same logic:



          Detail.js (subsequent screen in Stack navigator):



          componentDidMount() 
          this.backHandler = BackHandler.addEventListener("hardwareBackPress", () =>
          return this.props.navigation.navigate("Dashboard");
          );


          componentWillUnmount()
          this.backHandler.remove();






          share|improve this answer




















            Your Answer






            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "1"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader:
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            ,
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );













             

            draft saved


            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53232614%2freact-native-backhandler-with-alert%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            0
            down vote



            accepted










            Using the lifecycle alternative from the Documentation (https://facebook.github.io/react-native/docs/backhandler) seems to handle odd behaviour with Alert and return true;:



            Dashboard.js



            componentDidMount() 
            this.backHandler = BackHandler.addEventListener("hardwareBackPress", () =>
            Alert.alert("Logout", "Are you sure you want to logout?", [ text: "Cancel", onPress: () => , style: "cancel" , text: "Logout", onPress: () => this.handleLogout() ], cancelable: false );
            return true;
            );


            componentWillUnmount()
            this.backHandler.remove();


            handleLogout()
            global.screenName = "Dashboard";
            return this.props.navigation.navigate("Login");



            As long as all subsequent screens that need the back button overridden also use the same logic:



            Detail.js (subsequent screen in Stack navigator):



            componentDidMount() 
            this.backHandler = BackHandler.addEventListener("hardwareBackPress", () =>
            return this.props.navigation.navigate("Dashboard");
            );


            componentWillUnmount()
            this.backHandler.remove();






            share|improve this answer
























              up vote
              0
              down vote



              accepted










              Using the lifecycle alternative from the Documentation (https://facebook.github.io/react-native/docs/backhandler) seems to handle odd behaviour with Alert and return true;:



              Dashboard.js



              componentDidMount() 
              this.backHandler = BackHandler.addEventListener("hardwareBackPress", () =>
              Alert.alert("Logout", "Are you sure you want to logout?", [ text: "Cancel", onPress: () => , style: "cancel" , text: "Logout", onPress: () => this.handleLogout() ], cancelable: false );
              return true;
              );


              componentWillUnmount()
              this.backHandler.remove();


              handleLogout()
              global.screenName = "Dashboard";
              return this.props.navigation.navigate("Login");



              As long as all subsequent screens that need the back button overridden also use the same logic:



              Detail.js (subsequent screen in Stack navigator):



              componentDidMount() 
              this.backHandler = BackHandler.addEventListener("hardwareBackPress", () =>
              return this.props.navigation.navigate("Dashboard");
              );


              componentWillUnmount()
              this.backHandler.remove();






              share|improve this answer






















                up vote
                0
                down vote



                accepted







                up vote
                0
                down vote



                accepted






                Using the lifecycle alternative from the Documentation (https://facebook.github.io/react-native/docs/backhandler) seems to handle odd behaviour with Alert and return true;:



                Dashboard.js



                componentDidMount() 
                this.backHandler = BackHandler.addEventListener("hardwareBackPress", () =>
                Alert.alert("Logout", "Are you sure you want to logout?", [ text: "Cancel", onPress: () => , style: "cancel" , text: "Logout", onPress: () => this.handleLogout() ], cancelable: false );
                return true;
                );


                componentWillUnmount()
                this.backHandler.remove();


                handleLogout()
                global.screenName = "Dashboard";
                return this.props.navigation.navigate("Login");



                As long as all subsequent screens that need the back button overridden also use the same logic:



                Detail.js (subsequent screen in Stack navigator):



                componentDidMount() 
                this.backHandler = BackHandler.addEventListener("hardwareBackPress", () =>
                return this.props.navigation.navigate("Dashboard");
                );


                componentWillUnmount()
                this.backHandler.remove();






                share|improve this answer












                Using the lifecycle alternative from the Documentation (https://facebook.github.io/react-native/docs/backhandler) seems to handle odd behaviour with Alert and return true;:



                Dashboard.js



                componentDidMount() 
                this.backHandler = BackHandler.addEventListener("hardwareBackPress", () =>
                Alert.alert("Logout", "Are you sure you want to logout?", [ text: "Cancel", onPress: () => , style: "cancel" , text: "Logout", onPress: () => this.handleLogout() ], cancelable: false );
                return true;
                );


                componentWillUnmount()
                this.backHandler.remove();


                handleLogout()
                global.screenName = "Dashboard";
                return this.props.navigation.navigate("Login");



                As long as all subsequent screens that need the back button overridden also use the same logic:



                Detail.js (subsequent screen in Stack navigator):



                componentDidMount() 
                this.backHandler = BackHandler.addEventListener("hardwareBackPress", () =>
                return this.props.navigation.navigate("Dashboard");
                );


                componentWillUnmount()
                this.backHandler.remove();







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Nov 9 at 20:19









                Tim Lewis

                10.2k63358




                10.2k63358



























                     

                    draft saved


                    draft discarded















































                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53232614%2freact-native-backhandler-with-alert%23new-answer', 'question_page');

                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Use pre created SQLite database for Android project in kotlin

                    Darth Vader #20

                    Ondo