3

I want to use react's setState with chrome API but I'm running into an issue...

componentDidMount() {

    chrome.runtime.onMessage.addListener(function(request, sender) {
        if (request.action == "getSource") {
            this.setState({sourceCode: request.source});
        }
    }); 
}

I tried the following but chrome API does not recognize setState as a function, so then I tried to first save request.source as a variable...

componentDidMount() {
    var source = "";
    chrome.runtime.onMessage.addListener(function(request, sender) {
        if (request.action == "getSource") {
            source = request.source;
        }
    });
    this.setState({sourceCode: source});
}

But when I try the following, source remains an empty string. I cannot figure out why since source is being set to request.source. How can I fix this?

EDIT

I am calling a script as so...

chrome.tabs.executeScript(null, {
        file: 'src/js/scripts/getPageSource.js'
     }, function() {
     ...

and inside the script I have the following...

chrome.runtime.sendMessage({
    action: "getSource",
    source: DOMtoString(document)
});

Where DOMtoString function simply returns a string. It is the caught by my componentDidMount which I have verified by printing to the console inside the if statement.

It has come to my attention that the addListener is asynchronous. Is there any way I can save the result in the state?

9
  • Please edit the question to be on-topic: include a complete minimal reproducible example that duplicates the problem. Including a manifest.json, some of the background and content scripts. Questions seeking debugging help ("why isn't this code working?") must include: ►the desired behavior, ►a specific problem or error and ►the shortest code necessary to reproduce it in the question itself. Questions without a clear problem statement are not useful to other readers. See: "How to create a minimal reproducible example", What topics can I ask about here?, and How to Ask. Commented Nov 9, 2016 at 17:54
  • 1
    Are you aware that setState is asunchronous? If you want to see the result you have to ask for them inside a callback function within setState(). ie: this.setState({sourceCode: source}, function(){ console.log(this.state.sourceCode) }) Commented Nov 9, 2016 at 18:03
  • 1
    We need to see how you send that source and what's really inside it obviously :-) Also, yeah, you're incorrectly using asynchronous js as Falk noted. Commented Nov 9, 2016 at 18:04
  • 1
    Possible duplicate: Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference Commented Nov 9, 2016 at 18:06
  • 2
    I think this is completely on topic, not sure why this is flagged. In any case you're hitting two classic javascript issues. 1) setState is not a function because this is getting rebound by your callback function stackoverflow.com/questions/31045716/… and 2) source is an empty string because your setstate call will be fired before your callback function above Commented Nov 9, 2016 at 18:08

1 Answer 1

3

You need to bind this so it is unchanged in the event listener

chrome.runtime.onMessage.addListener(function(request, sender) {
    if (request.action == "getSource") {
        this.setState({sourceCode: request.source});
    }
}.bind(this));

Your second attempt doesn't work because the callback is asynchronous. You need to call setState when the callback returns. In your second attempt, you register for the listener but then immediately call setState.

Edit: Alternatively, you could switch to using arrow functions instead. This would lexically bind this so it would be unchanged.

chrome.runtime.onMessage.addListener((request, sender) => {
    if (request.action == "getSource") {
        this.setState({sourceCode: request.source});
    }
});
Sign up to request clarification or add additional context in comments.

7 Comments

You're using react and JSX - easier to use =>
Agreed. I would add => as an option in your answer.
I was preferring the KISS approach but added it as an option.
@BenjaminGruenbaum, No, react and JSX are not the reason. => is available because this is running as a Chrome extension. Thus, you only have to consider Chrome as the browser, which supports => (from v45). In addition, other browsers in which such an extension might also be compatible (e.g. a Firefox WebExtension) also support =>.
@Makyen I think Benjamin was implying that OP is probably transpiling with babel already, so in fact the arrow function will not exist in the compiled code.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.