React Native Navigation override goBack() of header back button in Stack Navigator

Viewed 10802

I want to customize the behavior of the default back button in stack navigator locally to one screen.

In the details assuming that on the stack there are screen1|screen2, I want to pass some props from screen2 to screen1 once the button is pressed.

I spent a lot of time reading React navigation docs, searching on internet and coding but I am not able to do this.

FROM DOCS

It's possible that in some circumstances that you want to customize the back button more than you can through the options mentioned above, in which case you can set the headerLeft option to a React Element that will be rendered I know that the issue concerns the goBack() function of the headerRight component.

I want to override the default function goBack() related to the headerLeft back button with something like navigation.navigate("previousScreen",{{..props}}).

And ( this is very important!! ) I want to use this behavior locally to a specific screen, so not globally.

I have tried with something like this but doesn't works.

 export default function App(){
 return(
 <NavigationContainer>
  <Stack.Navigator>
    <Stack.Screen name="FirstScreen" component={FirstScreen}/>
    <Stack.Screen name="SecondScreen" component={SecondScreen} options={{headerLeft: () => (
        <HeaderBackButton
          onPress={() =>navigation.navigate("FirstScreen",{//stuff//})}
          title="Info"
          color="#fff"
        />
      ),}}/>
  </Stack.Navigator>
</NavigationContainer>
 )}
4 Answers

If you are using react navigation v5, you can set the behaviour for a specific screen using :

import { HeaderBackButton } from '@react-navigation/stack';

...
options={{
          headerLeft: (props) => (
            <HeaderBackButton
              {...props}
              onPress={() => {
                navigation.navigate('screenName');
              }}
            />
          ),
        }}
...

You can also set as stack level using screenOptions={{}} instead.

"navigation" and "route" are also available on screen props.

options={({ navigation, route }) => ({headerLeft: ...})

When the component is mounted, register back button press listener

componentDidMount() {
    BackHandler.addEventListener('hardwareBackPress', this.onBackButtonPressAndroid)
}

componentWillUnmount() {
    BackHandler.removeEventListener('hardwareBackPress', this.onBackButtonPressAndroid)
}

Then in the function, you can check and handle the action, ex:

onBackButtonPressAndroid = () => {
    // Check if the current screen is focused or a subscreen is perhaps
    if (this.props.navigation.isFocused()) {
        if (someCondition) {
            // Do a navigation to a custom screen, pass props here if needed
            this.props.navigation.navigate('search')
            return true
            // Return true if you want to tell react navigation you've handled the back press
        }
        else if (this.state.offsetTop > 10) {
            // Ex. for scrolling to top
            this.scrollToTop()
            this.setState({
                offsetTop: 0,
            })
            return true
        }
    }
    // Return false if you want to tell react navigation you didn't handle the back press
    return false
}

Try passing navigationOptions to a specific screen :

export default function App(){
 return(
 <NavigationContainer>
  <Stack.Navigator>
    <Stack.Screen name="FirstScreen" component={FirstScreen}/>
    <Stack.Screen name="SecondScreen" component={SecondScreen}
       navigationOptions: ({ navigation }) => ({ headerLeft: (<HeaderBackButton onPress={() => {}}/>)
    })}}/>
  </Stack.Navigator>
</NavigationContainer>
 )}

Either you can specify it there on the navigation. Or on the Second screen, try this :

class SecondScreen extends React.Component {
  static navigationOptions = {
    headerLeft: (
      <Button
        onPress={() => alert('This is a back button!')}
        title="Title"
        color="#fff"
      />
    ),
  };
}

For react-navigation v6, you can use setOptions inside a useEffect

import { HeaderBackButton } from '@react-navigation/elements';

...

const ChatScreen = ({navigation}) => {

     useEffect( () => {
            navigation.setOptions({ headerShown: true,
                                    headerLeft: (props) => (
                                        <HeaderBackButton
                                            {...props}
                                            onPress={() => {
                                                navigation.navigate('MyScreen');
                                            }}
                                        />
                                    )
                                  });
        } ); 
}
Related