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
2
Answers
You can achieve the desired behavior by using a combination of
headerLeft
andonNavigationStateChange
in yourWebViewScreen
. Here’s a modified version of yourWebViewScreen
that should help you implement the combined back functionality:In this code, the
handleNavigationStateChange
function checks if the WebView can go back (canGoBack
). It then updates theheaderLeft
button 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.
I have never worked with
WebView
, I normally use React Native for Android/iOS dev, still, I have an idea that might work.Just do this ( hope you know how to use React Context, if not comment it, I will update the answer ) :
const [history, setHistory] = useState([])
Context
and puthistory
andsetHistory
invalue
attribute.history.push('WebPage name')
, this way you can know if there are pages in background and which and how many.history.length?
to see if array has any element, if yes you can do go back to last webpage bywebViewRef.current?.goBack()
, else you can donavigation.goBack()
to navigate to last screen.Overall it will look like this :
// go Back button
Using Context is really easy, comment if you don’t get anything, I will update my answer. Also upvote if this helps, just need a few more reputations 🙂