Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The method stopLoading of react-native-webview causes the website to freeze

Tags:

I want to intercept clicks on a link in my webview in react-native and perform a custom action instead of navigating to the target of the link as described in the official guide. Here's what I do:

import React from 'react';
import {View, Linking} from 'react-native';
import AsyncStorage from '@react-native-community/async-storage';
import {WebView} from 'react-native-webview';

export default class WebViewScreen extends React.Component {
    static navigationOptions = {
        title: 'Produck',
    };

    constructor(props) {
        super(props);
    }

    /**
     * Defines content and look of the WebViewScreen.
     */
    render() {
        const DEFAULT_URL = "https://www.myurl.de/index.html";

        return (
            <View style={{ flex: 1 }}>
                <WebView
                    ref = {webview => {
                        this.myWebView = webview;
                    }}
                    renderLoading = {this.renderLoading}
                    startInLoadingState = {true}
                    automaticallyAdjustContentInsets = {true}
                    source = {{ uri: DEFAULT_URL }}
                    javaScriptEnabled = {true}
                    domStorageEnabled = {true}
                    cacheEnabled = {false}
                    useWebKit = {true} // use WKWebView on iOS (http://facebook.github.io/react-native/blog/2018/08/27/wkwebview)
                    onNavigationStateChange={this.handleWebViewNavigationStateChange.bind(this)}
                />
            </View>
        );
    }

    handleWebViewNavigationStateChange = newNavState => {
        const {url} = newNavState;
        if (!url) return;

        if (isExternal(url)) {
            this.myWebView.stopLoading();

            // do something else, e.g.
            Linking.openURL(url);
        }
    };

}

If I click on a link in that webview the URL will be opened in a the systems Browser as expected. The problem is however that afterwards the webview is frozen. I can't click any more Links or even scroll the page. Of course this is not as it should be. The whole point is to open a link somewhere else so that the page in the webview remains usable. The result will remain the same, even if I remove the Linking-part. Then the page just freezes on a link-click.

Does anyone know what to do? I guess the stopLoading-method does a little more than just abort loading. Does it maybe also cancel any running Javascript on the current page? If so, can I prevent that?

like image 848
Fencer Avatar asked Jul 15 '19 15:07

Fencer


1 Answers

I have found a solution at least for my case thanks to this pull request. Instead of using onNavigationStateChange and stopLoading I turned to onShouldStartLoadWithRequest. In the callback method for this event you can define whether or not the request should be discarded as far as the current webview is concerned or not simply by returning false or true. So you get something like this:

render() {
    ...
    return(...
        <WebView
            ...
            onShouldStartLoadWithRequest={this.handleWebViewRequest.bind(this)}
            ...
        />
    );
}

handleWebViewRequest = request => {
    const {url} = request;
    if (!url) return false;

    if (isExternal(url)) {
        Linking.openURL(url);
        return false;
    } else {
        return true;
    }
}

So far for the "what to do"-part. Well I also wanted to answer my other questions and dug into the code of react-native-webview (which was no fun at all... what about comments? -> 'let the code speak' -> well it doesn't). After spending some time jumping from one delegation target to the next, somewhere the stopLoading-call seems to be handed over to the native WebView. So the behaviour may also be completely different for Android and iOS (I'm developing only for Android currently). As for the "can I prevent"-part of the whole question I can say: "No". Of course the most interesting part would have been "what does stopLoading actually do? Somewhere I read that it prevents Links on the current page from being clicked, indeed. But that was just a non-proven statement. As I got to the native Android-WebView-documentation I found the very very good explanation "Stops the current load." (go Google, yay). Then I lost all motivation to dig deeper. Well, unless someone more enlightned than me, can come up with a more elaborate explanation I will problably accept my own answer, since it is at least a solution to the dev-problem I faced.

like image 61
Fencer Avatar answered Sep 29 '22 06:09

Fencer