Skip to content

Commit d032064

Browse files
authored
Merge pull request react-navigation#89 from react-navigation/backhandler-update
Update custom-android-back-button-handling.md
2 parents 349a270 + 82b8d51 commit d032064

File tree

1 file changed

+33
-6
lines changed

1 file changed

+33
-6
lines changed

docs/custom-android-back-button-handling.md

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ sidebar_label: Custom Android back button behavior
66

77
By default, when user presses the Android hardware back button, react-navigation will pop a screen or exit the app if there are no screens to pop. This is a sensible default behavior, but there are situations when you might want to implement custom handling.
88

9-
Take, for example, a screen where user is selecting items in a list, and a "selection mode" is active. On a back button press, you would first want the "selection mode" to be deactivated, and the screen should be popped only on the second back button press. The following code snippet demostrates the situation. We make use of [`BackHandler`](https://facebook.github.io/react-native/docs/backhandler.html) which comes with react-native to add our custom `hardwareBackPress` listener.
9+
If you're looking for an easy-to-use solution, you can check out a community-developed package [react-navigation-backhandler](https://github.com/vonovak/react-navigation-backhandler). The following text will show you how the package actually works under the cover.
10+
11+
As an example, consider a screen where user is selecting items in a list, and a "selection mode" is active. On a back button press, you would first want the "selection mode" to be deactivated, and the screen should be popped only on the second back button press. The following code snippet demostrates the situation. We make use of [`BackHandler`](https://facebook.github.io/react-native/docs/backhandler.html) which comes with react-native and we [subscribe to navigation lifecycle updates](navigation-prop.html#addlistener-subscribe-to-updates-to-navigation-lifecycle) to add our custom `hardwareBackPress` listener.
1012

1113
Returning `true` from `onBackButtonPressAndroid` denotes that we have handled the event, and react-navigation's listener will not get called, thus not popping the screen. Returning `false` will cause the event to bubble up and react-navigation's listener will pop the screen.
1214

@@ -15,12 +17,20 @@ import React from "react";
1517
import { BackHandler } from "react-native";
1618
1719
class ScreenWithCustomBackBehavior extends React.Component {
18-
componentDidMount() {
19-
BackHandler.addEventListener('hardwareBackPress', this.onBackButtonPressAndroid);
20+
_didFocusSubscription;
21+
_willBlurSubscription;
22+
23+
constructor(props) {
24+
super(props);
25+
this._didFocusSubscription = props.navigation.addListener('didFocus', payload =>
26+
BackHandler.addEventListener('hardwareBackPress', this.onBackPressed)
27+
);
2028
}
2129
22-
componentWillUnmount() {
23-
BackHandler.removeEventListener('hardwareBackPress', this.onBackButtonPressAndroid);
30+
componentDidMount() {
31+
this._willBlurSubscription = this.props.navigation.addListener('willBlur', payload =>
32+
BackHandler.removeEventListener('hardwareBackPress', this.onBackButtonPressAndroid)
33+
);
2434
}
2535
2636
onBackButtonPressAndroid = () => {
@@ -31,7 +41,24 @@ class ScreenWithCustomBackBehavior extends React.Component {
3141
return false;
3242
}
3343
};
44+
45+
componentWillUnmount() {
46+
this._didFocusSubscription && this._didFocusSubscription.remove();
47+
this._willBlurSubscription && this._willBlurSubscription.remove();
48+
}
49+
50+
render() {
51+
// ...
52+
}
3453
}
3554
```
3655

37-
The presented approach will work well for screens that are shown in a stack navigator. Custom back button handling in other situations may not be supported at the moment (eg. A known case when this does not work is when you want to handle back button press in an open drawer. PRs for such use cases are welcome!)
56+
The presented approach will work well for screens that are shown in a `StackNavigator`. Custom back button handling in other situations may not be supported at the moment (eg. A known case when this does not work is when you want to handle back button press in an open drawer. PRs for such use cases are welcome!).
57+
58+
### Why not use component lifecycle methods?
59+
60+
At first, you may be inclined to use `componentDidMount` to subscribe for the back press event and `componentWillUnmount` to unsubscribe. Reason why we do not use them is that they are not generally called when entering or leaving a screen.
61+
62+
More specifically, consider a `StackNavigator` with screens `A` and `B`. After navigating to `A`, its `componentDidMount` is called. When pushing `B`, its `componentDidMount` is also called, but `A` remains mounted and its `componentWillUnmount` is therefore not called.
63+
64+
Similarly, when going back from `B` to `A`, `componentWillUnmount` of `B` is called, but `componentDidMount` of `A` is not because `A` remained mounted the whole time.

0 commit comments

Comments
 (0)