Skip to content

Commit b64b5de

Browse files
committed
Improve custom back button handling docs
1 parent 0790147 commit b64b5de

File tree

2 files changed

+26
-33
lines changed

2 files changed

+26
-33
lines changed

docs/community-libraries-and-navigators.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,14 @@ Provides simple HOCs that map react-navigation props to your screen components d
6060

6161
[github.com/vonovak/react-navigation-props-mapper](https://github.com/vonovak/react-navigation-props-mapper)
6262

63+
## react-navigation-backhandler
64+
65+
Easily handle Android back button behavior with React-Navigation with a component based API.
66+
67+
#### Links
68+
69+
[github.com/vonovak/react-navigation-backhandler](https://github.com/vonovak/react-navigation-backhandler)
70+
6371
## react-native-header-scroll-view
6472

6573
This component implements [iOS large header with grow/shrink on scroll](https://react-navigation.canny.io/feature-requests/p/ios-11-large-header-and-growshrink-on-scroll), made by [@jonsamp](https://github.com/jonsamp). Note that it doesn't handle header animation between screens, it only handles animating the header title on scroll.

website/versioned_docs/version-4.x/custom-android-back-button-handling.md

Lines changed: 18 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ original_id: custom-android-back-button-handling
77

88
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.
99

10-
> 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 shows what the package does under the cover.
11-
12-
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 demonstrates 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.
10+
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 demonstrates the situation. We make use of [`BackHandler`](https://facebook.github.io/react-native/docs/backhandler.html) which comes with react-native and add additional check (`navigation.isFocused()`) to make sure that our code only gets executed if the screen is focused.
1311

1412
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.
1513

@@ -18,54 +16,41 @@ import React from 'react';
1816
import { BackHandler } from 'react-native';
1917

2018
class ScreenWithCustomBackBehavior extends React.Component {
21-
_didFocusSubscription;
22-
_willBlurSubscription;
23-
24-
constructor(props) {
25-
super(props);
26-
this._didFocusSubscription = props.navigation.addListener(
27-
'didFocus',
28-
payload =>
29-
BackHandler.addEventListener(
30-
'hardwareBackPress',
31-
this.onBackButtonPressAndroid
32-
)
19+
componentDidMount() {
20+
BackHandler.addEventListener(
21+
'hardwareBackPress',
22+
this.handleBackButtonPressAndroid
3323
);
3424
}
3525

36-
componentDidMount() {
37-
this._willBlurSubscription = this.props.navigation.addListener(
38-
'willBlur',
39-
payload =>
40-
BackHandler.removeEventListener(
41-
'hardwareBackPress',
42-
this.onBackButtonPressAndroid
43-
)
26+
componentWillUnmount() {
27+
BackHandler.removeEventListener(
28+
'hardwareBackPress',
29+
this.handleBackButtonPressAndroid
4430
);
4531
}
4632

47-
onBackButtonPressAndroid = () => {
33+
handleBackButtonPressAndroid = () => {
34+
if (!this.props.navigation.isFocused()) {
35+
// The screen is not focused, so don't do anything
36+
return false;
37+
}
38+
4839
if (this.isSelectionModeEnabled()) {
4940
this.disableSelectionMode();
41+
42+
// We have handled the back button
43+
// Return `true` to prevent react-navigation from handling it
5044
return true;
5145
} else {
5246
return false;
5347
}
5448
};
5549

56-
componentWillUnmount() {
57-
this._didFocusSubscription && this._didFocusSubscription.remove();
58-
this._willBlurSubscription && this._willBlurSubscription.remove();
59-
}
60-
6150
render() {
6251
// ...
6352
}
6453
}
6554
```
6655

6756
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!).
68-
69-
### Why not use component lifecycle methods?
70-
71-
At first, you may be inclined to use `componentDidMount` to subscribe for the back press event and `componentWillUnmount` to unsubscribe. This approach will not work - learn more about this in [navigation lifecycle](navigation-lifecycle.html).

0 commit comments

Comments
 (0)