'BackHandler.removeEventListener is not wotking in react-native for android

Cannot get BackHandler.removeEventListener to work. Can anyone please guide as of how to use it?



Solution 1:[1]

An update on how to do it with hooks - I finally made it working by keeping the function we are passing in BackHandler.addEventListener inside useEffect only and with it by using isFocused method of navigation. Any change in the following code breaks it -

useEffect(() => {
    const backAction = () => {
        if (navigation.isFocused()) {
            Alert.alert("Hold on!", "Are you sure you want to exit the app?", [
                {
                    text: "Cancel",
                    onPress: () => null,
                    style: "cancel"
                },
                { text: "YES", onPress: () => BackHandler.exitApp() }
            ]);
            return true;
        }

    };
    const backHandler = BackHandler.addEventListener("hardwareBackPress", backAction);
    return () => backHandler.remove();
}, [])

This is my second answer, if it helps please mark this as useful.

Solution 2:[2]

This is also quite same answer, but safe handling added.

    constructor(props) {
        super(props);
        this.backHandler = null;
     }

    componentDidMount() {
        if (this.backHandler)
          this.backHandler.remove();
        this.backHandler = BackHandler.addEventListener('backPress', this.handleBackButton.bind(this));
      }

    componentWillUnmount() {
        if (this.backHandler)
          this.backHandler.remove();
      }

    handleBackButton() {
        return true;
      }

Solution 3:[3]

I used it in functional component :

useEffect(() => {
    const backhandler = BackHandler.addEventListener('hardwareBackPress', () => {
        return true;
    });
    return () => {
        backhandler.remove();
    };
}, []);

Solution 4:[4]

I have faced this issue a lot.If we use addEventListener & removeEventListener, it will removeEventListener only when we reset/navigate to other stacks.

Suppose we want to restrict the back option on initial page:

Stack:

->screen1(we should prevent back option here and also we pass props to screen2)

->screen2(it will send some results to screen1)

->other screens ...

In that case removeEventListener is not working.

So, i have solved this issue on getStateForAction.This it the following code i have used.


const defaultGetStateForAction = PrimaryNavigation.router.getStateForAction;
PrimaryNavigation.router.getStateForAction = (action, state) => {
  if (Platform.OS === "android") {
    const screen = state ? state.routes[state.index] : null;
    if (
      action.type === NavigationActions.BACK &&
      screen &&
      (screen.routeName === "Register" ||
        screen.routeName === "OwnerDashboard" ||
        screen.routeName === "LandingPage" ||
        screen.routeName === "OptionPage" ||
        (screen.routeName === "loginStack" && screen.index == 0) 
        || (screen.routeName === "driverStack" &&
          screen.index == 0 &&
          screen.routes[screen.index].index == 0 )
        || (
          screen.routeName === "ownerStack" &&
          screen.index == 0 &&
          screen.routes[screen.index].index == 0
        )
      )*Note:Please mention whatever condition you desire*
    ) {
      Alert.alert(
        "Are you sure",
        "You want to exit the App",
        [
          {
            text: "Cancel",
            onPress: () => console.log("Cancel Pressed"),
            style: "cancel"
          },
          { text: "OK", onPress: () =>{ BackHandler.exitApp() }}
        ],
        { cancelable: false }
      );
      console.log("action",action,"state",state);
      return null;
    }
    else{
      return defaultGetStateForAction(action, state);
    }
  }
  else{
    return defaultGetStateForAction(action, state);
  }
};

<PrimaryNavigation ref={nav => (this.primaryNavigator = nav)} />

Here the PrimaryNavigation is the SwitchNavigator

const PrimaryNavigation = createSwitchNavigator(
  {
    splash: { screen: Splash },
    initialStack: { screen: InitialStack },
    stack2: { screen: Stack2 },
    stack3: { screen: Stack3 },

    DriverRegistrationStack: { screen: DriverRegistrationStack },
    OwnerRegistrationStack: { screen: OwnerRegistrationStack }
  },
  {
    initialRouteKey: "splash",
    headerMode: "none",
    navigationOptions: {
      gesturesEnabled: false
    }
  }
);

Solution 5:[5]

@Johncy is correct. The event listener will only be removed when your navigation stack is reset. This is the case if you are using React Native Navigation. The solution is to toggle if back press is available on each screen:

let isBackPressAvailable = false;

/**
 * Toggles back press
 * 
 * @param {*} enabled 
 */
export const toggleBackPress = (enabled = true) => {
  isBackPressAvailable = enabled;
}

/**
 * Handlers Android back button press
 *
 * @param appName
 *
 * @return {boolean}
 */
export const handleBackPress = () => {
  if(isBackPressAvailable){
    // DO STUFF HERE

    return true;
  }

  return false;
};

Setup the listener when your app is opened:

BackHandler.addEventListener("hardwareBackPress", handleBackPress);

Then you can use toggleBackPress(true/false) to enable / disable custom behaviour for back press on each screen.

Solution 6:[6]

try this:

for register

this.backhandler = BackHandler.addEventListener('hardwareBackPress', () => {
  return true;
});

for remove (the best option is in the navigation not in componentWillUnmount)

this.backhandler.remove();

Solution 7:[7]

If you are using react navigation you should try this.

    useFocusEffect(
    React.useCallback(() => {

        BackHandler.addEventListener('hardwareBackPress', backAction);

        return () =>
            BackHandler.removeEventListener('hardwareBackPress', backAction);
    }, [])
);

const backAction = () => {
    Alert.alert("Hold on!", "Are you sure you want to go exit?", [
        {
            text: "Cancel",
            onPress: () => null,
            style: "cancel"
        },
        {text: "YES", onPress: () => BackHandler.exitApp()}
    ]);
    return true;
};

Solution 8:[8]

import { useIsFocused } from '@react-navigation/native'

const isFocused = useIsFocused()

const myCallback = () => {

console.log("myCallback is running...")

}

useEffect(() => {

    if (isFocused) {
        BackHandler.addEventListener("hardwareBackPress", myCallback)
    }

    return () => {
        BackHandler.removeEventListener("hardwareBackPress", myCallback)
    }

}, [isFocused])

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Rohit Advani
Solution 2 Sanjeev Rao
Solution 3 masud_moni
Solution 4 Johncy
Solution 5 Luke Brandon Farrell
Solution 6 blackgreen
Solution 7 Salih Kiraz
Solution 8 Mariana Reis Silveira