Bolboa Bolboa - 29 days ago 8
React JSX Question

How to use react setState with chrome API

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?

Answer

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});
    }
});