I am developing a trivia game, I am using react-navigation to handle navigation, I have 3 components, (newGame, Questions, Results ) I don't want the user to go back to the questions from the results page if the no. of questions has been exhausted, however, pressing the back button ( Android Hardware ) is taking him back to the questions. I then tried to handle the hardware back button like so:
componentWillMount() {
this.props.gameState(true);
BackHandler.addEventListener('hardwareBackPress', () => {
if (this.props.gamePlaying) { // Currently set to true. I will set it to false again on NewGame Page.
this.props.navigation.navigate('NewGame');
}
});
}
However, this is taking the user to the NewGame screen but immediately, it is bouncing back to the results page as it is firing the NAVIGATION/BACK as well immediately in the NewGame page. Which is again taking it back to the results page.
Possible fix?
I want to stop the the back button to fire after I have landed in the NewGame component page. Is there a way to do it?
My Environment
react-navigation = ^1.0.0-beta.11
react-native = 0.44.0
You need to return true
to indicate you have handled the back button yourself as you can see in the docs.
if one subscription returns true then subscriptions registered earlier will not be called
Your code should look like this:
componentWillMount() {
this.props.gameState(true);
BackHandler.addEventListener('hardwareBackPress', () => {
if (this.props.gamePlaying) {
this.props.navigation.navigate('NewGame');
return true; // This will prevent the regular handling of the back button
}
return false;
});
}
One way to stop the button from functioning is to introduce logic into your BackHandler eventlistener when you start it, like this:
BackHandler.addEventListener('hardwareBackPress', () => {
const { dispatch, nav } = this.props
if (nav.routes.length === 1 && (nav.routes[0].routeName === 'Login' || nav.routes[0].routeName === 'Start')) return false
dispatch({ type: 'Navigation/BACK' })
return true
})
Notice how we are observing conditions. The key to this question is to return true
or false
from the event listener. false
stops the Hardware Back Button from functioning. true
clean-exits from the event.
Here is another example to illustrate:
BackHandler.addEventListener('hardwareBackPress', () => {
const { dispatch, nav } = this.props
if (nav.routes[0].routeName === 'TriviaQuestion') return false
if (!playTimeLeft && (nav.routes[0].routeName === 'TriviaQuestion')) return false
if (nav.routes[0].routeName === 'InvasiveDialog') return false
dispatch({ type: 'Navigation/BACK' })
return true
})
Here is some sample code that is useful to look at for more purposes than just stopping the Back Button from functioning:
import React, { Component } from 'react'
import { Platform, BackHandler } from 'react-native'
import { Provider, connect } from 'react-redux'
import { addNavigationHelpers } from 'react-navigation'
import { NavigationStack } from './navigation/nav_reducer'
import store from './store'
class App extends Component {
componentWillMount() {
if (Platform.OS !== 'android') return
BackHandler.addEventListener('hardwareBackPress', () => {
const { dispatch, nav } = this.props
if (nav.routes.length === 1 && (nav.routes[0].routeName === 'Login' || nav.routes[0].routeName === 'Start')) return false
dispatch({ type: 'Navigation/BACK' })
return true
})
}
componentWillUnmount() {
if (Platform.OS === 'android') BackHandler.removeEventListener('hardwareBackPress')
}
render() {
const { dispatch, nav } = this.props
const navigation = addNavigationHelpers({
dispatch,
state: nav
})
return <NavigationStack navigation={navigation} />
}
}
const mapStateToProps = ({ nav }) => ({ nav })
const RootNavigationStack = connect(mapStateToProps)(App)
const Root = () => (
<Provider store={store}>
<RootNavigationStack />
</Provider>
)
export default Root
If you find this post while trying to make your Back Button simply work, then just copy my last example as closely as possible. Use the event listener exactly as shown and test your app first to see how it works.
If you are using Redux, this is what you want.
NavigationStack
simply refers to export const NavigationStack = StackNavigator({ ...etc })
in another file.
when user switch between screens in StackNavigator there is a back button by default, we can fix it by setting : headerLeft to null
static navigationOptions =({navigation}) => {
return {
title: 'Rechercher une ville',
headerLeft: null,
}
}