I'm learning navigation in React Native, and can't figure out way how to conditionally use one Back Button. Wanted behaviour would be like this - if user navigate between screens, he can press Go Back button, but if one of the screens contains WebView and he already visited few pages there, user would go back through this webview pages first, then Screens. Hope that makes sense. Something like that: Screen A <- Screen B <- Screen C with WebView <- Webview Page 1 <- Webview Page 2
AppScreen
import React from 'react';
import {Pressable, StyleSheet, Text} from 'react-native';
import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import HomeScreen from './src/screens/HomeScreen';
import WebViewScreen from './src/screens/WebViewScreen';
import ParamsScreen from './src/screens/ParamsScreen';
const Stack = createNativeStackNavigator();
function App(): React.JSX.Element {
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName="Home"
screenOptions={
({navigation}) => {}
}>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{title: 'Customized Header Home'}}
/>
<Stack.Screen
name="WebView Screen"
component={WebViewScreen}
options={({navigation, route}) => ({
title: 'Webview',
headerLeft: () => (
<Pressable onPress={() => navigation.goBack()}>
<Text style={{color: 'blue'}}>Go Back within Screens</Text>
</Pressable>
),
})}
/>
<Stack.Screen name="Params Screen" component={ParamsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
const styles = StyleSheet.create({});
export default App;
WebViewScreen
import {StyleSheet, Text, View, ActivityIndicator, Button} from 'react-native';
import React, {useRef, useState} from 'react';
import {WebView} from 'react-native-webview';
const WebViewScreen = ({navigation, route}) => {
const webViewRef = useRef<WebView>(null);
return (
<>
<View style={{flex: 0, alignItems: 'center', justifyContent: 'center'}}>
<Text>WebView Screen</Text>
<Button
title="Go Back within WebView"
onPress={() => webViewRef.current?.goBack()}
/>
</View>
<WebView
source={{uri: 'https://google.com'}}
startInLoadingState
ref={webViewRef}
renderLoading={() => (
<View style={{flex: 1, alignItems: 'center'}}>
<ActivityIndicator size="large" />
</View>
)}
allowsBackForwardNavigationGestures
onNavigationStateChange={navState => {}}
/>
</>
);
};
export default WebViewScreen;
const styles = StyleSheet.create({});
At the moment I've managed to have two separate working buttons, but it would be much better to have one back button in the header. I was playing with Screen options and onNavigationStateChange params, and but kind of got lost there.
I guess I would need some kind of function like this:
const goBack = () => {
if (webViewRef.current) {
webViewRef.current.goBack();
} else {
navigation.goBack();
}
};
but not sure how to integrate it with Stack.Navigator
You can achieve the desired behavior by using a combination of
headerLeftandonNavigationStateChangein yourWebViewScreen. Here's a modified version of yourWebViewScreenthat should help you implement the combined back functionality:In this code, the
handleNavigationStateChangefunction checks if the WebView can go back (canGoBack). It then updates theheaderLeftbutton accordingly. If the WebView can go back, the button will triggerwebViewRef.current.goBack(), otherwise, it will triggernavigation.goBack()to go back in the navigation stack.This way, you have a single "Go Back" button in the header that handles both WebView and screen navigation.