2

I'm really struggling to understand how to read and set this.state inside of functions called by WebView when doing specific operations. My end goal is to:

  • Show a activity indicator when the user clicks a link inside the webview
  • Perform certain actions based on the URL the user is clicking on

I'm very new to React, but from what I've learned, I should use () => function to bind this from the main object to be accessible inside the function.

This works on onLoad={(e) => this._loading('onLoad Complete')} and I can update the state when the page loaded the first time.

If I use onShouldStartLoadWithRequest={this._onShouldStartLoadWithRequest} I can see that it works and my console.warn() is shown on screen. this.state is of course not available.

However if I change it to onShouldStartLoadWithRequest={() => this._onShouldStartLoadWithRequest} the function doesn't seem to be executed at all, and neither this.state (commented in the code below) or console.warn() is run.

Any help is appreciated!

import React, { Component} from 'react';
import {Text,View,WebView} from 'react-native';

class Question extends Component {
    constructor(props) {
        super(props);
        this.state = {
            isLoading: false,
            debug: 'Debug header'
        };
    }

    render() {
        return (
            <View style={{flex:1, marginTop:20}}>
                <Text style={{backgroundColor: '#f9f', padding: 5}}>{this.state.debug}</Text>
                <WebView
                    source={{uri: 'http://stackoverflow.com/'}}
                    renderLoading={this._renderLoading}
                    startInLoadingState={true}
                    javaScriptEnabled={true}
                    onShouldStartLoadWithRequest={this._onShouldStartLoadWithRequest}
                    onNavigationStateChange = {this._onShouldStartLoadWithRequest} 
                    onLoad={(e) => this._loading('onLoad Complete')}
                />
            </View>
        );
    }

    _loading(text) {
        this.setState({debug: text});
    }

    _renderLoading() {
        return (
            <Text style={{backgroundColor: '#ff0', padding: 5}}>_renderLoading</Text>
        )
    }

    _onShouldStartLoadWithRequest(e) {
        // If I call this with this._onShouldStartLoadWithRequest in the WebView props, I get "this.setState is not a function"
        // But if I call it with () => this._onShouldStartLoadWithRequest it's not executed at all,
        // and console.warn() isn't run
        //this.setState({debug: e.url});
        console.warn(e.url);
        return true;
    }

}



module.exports = Question;
Niclas
  • 1,362
  • 1
  • 11
  • 24

1 Answers1

3

To access correct this (class context) inside _onShouldStartLoadWithRequest, you need to bind it with class context, after binding whenever this method will get called this keyword inside it will point to react class.

Like this:

onShouldStartLoadWithRequest={this._onShouldStartLoadWithRequest.bind(this)}

or use arrow function like this:

onShouldStartLoadWithRequest={this._onShouldStartLoadWithRequest}

_onShouldStartLoadWithRequest = (e) => {...}

Or like this:

onShouldStartLoadWithRequest={(e) => this._onShouldStartLoadWithRequest(e)}

Check this answer for more details: Why is JavaScript bind() necessary?

Mayank Shukla
  • 100,735
  • 18
  • 158
  • 142
  • Great, it worked regarding the this.state binding, however I get **undefined is not an object (evaluating ’e.url’)**. The function is `_onShouldStartLoadWithRequest(e)` and should contain e.url, which it did when I didn't bind. – Niclas Apr 12 '17 at 11:44
  • check the updated answer, in case of arrow function you need to pass the `e`, try now. btw first way should work when u use `.bind(this)`. – Mayank Shukla Apr 12 '17 at 11:46
  • For some reason the first one works perfectly, the second one returns undefined for e.url. Thank you very much! – Niclas Apr 12 '17 at 12:10