Reputation: 3
I am dealing with the following frustrating error:
Home.js:231 Uncaught (in promise) TypeError: _this9.setState is not a function. The error is coming from the last line of the following function:
checkIfRunning() {
return fetch('/api/following/iscurrentlyrunning', {
credentials: 'include',
})
.then(response => {
console.log(response.status);
if (response.status === 200) {
return response.json();
}
})
.then(response => {
let cState = this.state;
cState.running = response;
this.setState(cState);
});
}
I did bind the function in the component constructor and when I call it alone, it works fine. The issue arise when I try to invoke the function in a timer (setInterval). In componentWillMount, I call few functions:
componentWillMount() {
this.checkIfFirstTimeLogin()
.then(() => {
// user already exists
if (!this.state.firstLogin) {
this.Name();
this.getRole();
setInterval(() => this.checkIfRunning(), 10000);
}
})
.then(() => {
let cState = this.state;
cState.pageLoading = false;
this.setState(cState);
})
.catch(error => console.log(error));
}
I have the intuition that the promise chain breaks the binding for a reason I do not presently understand.
Thank you for any help,
Upvotes: 0
Views: 2731
Reputation: 91
You are mutating the state directly, it is not allowed, in the final example you are still doing it. It is better to use an Object.assign(…)
to create new object like this :
let newState = Object.assign({}, ...this.state, running: response);
Then, only do your setState()
call
this.setState(newState);
One of the fundamental principles of React is that changes to State are not done directly but with the setState
function which will put the change to queue, and it will be done either alone or with batch update.
Upvotes: 0
Reputation: 3
Thanks all for the help, very appreciated.
I solved the problem with the following fix, although I am not sure why it works now:
checkIfRunning() {
return fetch('/api/following/iscurrentlyrunning', {
credentials: 'include',
})
.then(response => {
console.log(response.status);
if (response.status === 200) {
return response.json();
}
})
.then(response => {
let cState = this.state;
cState.running = response;
this.setState({cState});
});
}
Notice how this.setState(cState) became this.setState({cState}).
Thanks all for your time, it led to interesting research on my part.
Upvotes: 0
Reputation: 365
You can try change function checkIfRunning() {}
to checkIfRunning = () => {}
to pass this
into function
Upvotes: 0
Reputation: 7008
Promises are a guaranteed future, which means the whole promise chain will fire once invoked and there's little you can do to stop it.
On a practical level, this means you need to check to be sure that your component instance is still mounted before trying to access setState off it, as the component may have unmounted before this promise chain completes.
.then(response => {
...code here...
// important! check that the instance is still mounted!
if (this.setState) {
this.setState(cState);
}
});
Also, you should never mutate local state directly as you are doing here:
// don't mutate state directly, use setState!
let cState = this.state;
cState.running = response;
Upvotes: 1