I am trying to replicate the Turbo Native behavior. I have a WebView, and every time a link is visited I want to make a transition and add it to the navigation stack. The problem is that when I do that with React Navigation, it re-renders from the beginning the WebView again for each screen. I would like to reuse the same WebView instance between screens when doing push and pop so I don't have to reload all the assets and javascript over and over again. Is there any way to do this? Thanks!
This is a sample code:
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
title="Go to Web View"
onPress={() => navigation.navigate('WebView', {
url: "https://someurl/"
})}
/>
</View>
);
}
function WebViewScreen({ route, navigation }) {
const webViewRef = useRef(null);
const [URL, setURL] = useState("");
const [title, setTitle] = useState("");
useFocusEffect(
useCallback(() => {
// Do something when the screen is focused
setURL(route.params.url);
setTitle(route.params.title);
return () => {
// Do something when the screen is unfocused
// Useful for cleanup functions
};
}, [])
);
useEffect(() => {
if (URL && URL != route.params.url) {
navigation.push(route.name, {
url: URL,
title: title,
});
}
}, [URL]);
useEffect(() => {
if (title && !route.params.title) {
navigation.setOptions({ title: title })
} else {
navigation.setOptions({ title: route.params.title })
}
}, [title]);
const handleNavigation = (syntheticEvent) => {
const { url, title } = syntheticEvent.nativeEvent;
if (!url) return;
setURL(url);
setTitle(title);
};
const runFirst = `
setTimeout(function() { window.ReactNativeWebView.postMessage("Hello!") }, 2000);
true; // note: this is required, or you'll sometimes get silent failures
`;
return (
<Freeze freeze={!webViewRef}>
<WebView
ref={webViewRef}
style={styles.container}
source={{ uri: route.params.url }}
originWhitelist={['*']}
allowingReadAccessToURL={'*'}
allowFileAccess
allowFileAccessFromFileURLs
allowUniversalAccessFromFileURLs
javaScriptEnabled
javaScriptCanOpenWindowsAutomatically
domStorageEnabled
mixedContentMode={'always'}
onLoadEnd={handleNavigation}
injectedJavaScript={runFirst}
onMessage={(event) => {
alert(event.nativeEvent.data);
}}
/>
</Freeze>
);
}
const HomeStack = createNativeStackNavigator();
function HomeStackScreen() {
return (
<HomeStack.Navigator>
<HomeStack.Screen name="Inicio" component={HomeScreen} />
<HomeStack.Screen
name="WebView"
component={WebViewScreen}
initialParams={{
url: "https://someurl/"
}}
/>
</HomeStack.Navigator>
);
}
The injectedJavaScript property injects javascript on the first load of the webview. Here, on each request it is executing that code, and it should only do so once. This is a way to test it.